Java tutorial
/* * Copyright 2013-2014 eBay Software Foundation * * Licensed 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 com.kylinolap.rest.service; import java.io.IOException; import java.io.Serializable; import java.lang.reflect.Field; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.NavigableMap; import org.apache.commons.io.IOUtils; import org.apache.hadoop.hbase.client.Delete; import org.apache.hadoop.hbase.client.Get; import org.apache.hadoop.hbase.client.HTableInterface; import org.apache.hadoop.hbase.client.Put; import org.apache.hadoop.hbase.client.Result; import org.apache.hadoop.hbase.client.ResultScanner; import org.apache.hadoop.hbase.client.Scan; import org.apache.hadoop.hbase.filter.CompareFilter.CompareOp; import org.apache.hadoop.hbase.filter.SingleColumnValueFilter; import org.apache.hadoop.hbase.util.Bytes; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.acls.domain.AccessControlEntryImpl; import org.springframework.security.acls.domain.AclAuthorizationStrategy; import org.springframework.security.acls.domain.AclImpl; import org.springframework.security.acls.domain.AuditLogger; import org.springframework.security.acls.domain.GrantedAuthoritySid; import org.springframework.security.acls.domain.ObjectIdentityImpl; import org.springframework.security.acls.domain.PermissionFactory; 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.ChildrenExistException; import org.springframework.security.acls.model.MutableAcl; import org.springframework.security.acls.model.MutableAclService; import org.springframework.security.acls.model.NotFoundException; import org.springframework.security.acls.model.ObjectIdentity; import org.springframework.security.acls.model.PermissionGrantingStrategy; import org.springframework.security.acls.model.Sid; import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.util.FieldUtils; import org.springframework.stereotype.Component; import org.springframework.util.Assert; import com.kylinolap.common.KylinConfig; import com.kylinolap.common.persistence.HBaseConnection; import com.kylinolap.rest.util.Serializer; /** * @author xduo * */ @Component("aclService") public class AclService implements MutableAclService { private static final Logger logger = LoggerFactory.getLogger(AclService.class); public static final String ACL_INFO_FAMILY = "i"; public static final String ACL_ACES_FAMILY = "a"; private static final String DEFAULT_TABLE_PREFIX = "kylin_metadata"; private static final String ACL_TABLE_NAME = "_acl"; private static final String ACL_INFO_FAMILY_TYPE_COLUMN = "t"; private static final String ACL_INFO_FAMILY_OWNER_COLUMN = "o"; private static final String ACL_INFO_FAMILY_PARENT_COLUMN = "p"; private static final String ACL_INFO_FAMILY_ENTRY_INHERIT_COLUMN = "i"; private Serializer<SidInfo> sidSerializer = new Serializer<SidInfo>(SidInfo.class); private Serializer<DomainObjectInfo> domainObjSerializer = new Serializer<DomainObjectInfo>( DomainObjectInfo.class); private Serializer<AceInfo> aceSerializer = new Serializer<AceInfo>(AceInfo.class); private String hbaseUrl = null; private String tableNameBase = null; private String aclTableName = null; private final Field fieldAces = FieldUtils.getField(AclImpl.class, "aces"); private final Field fieldAcl = FieldUtils.getField(AccessControlEntryImpl.class, "acl"); @Autowired protected PermissionGrantingStrategy permissionGrantingStrategy; @Autowired protected PermissionFactory aclPermissionFactory; @Autowired protected AclAuthorizationStrategy aclAuthorizationStrategy; @Autowired protected AuditLogger auditLogger; public AclService() { String metadataUrl = KylinConfig.getInstanceFromEnv().getMetadataUrl(); // split TABLE@HBASE_URL int cut = metadataUrl.indexOf('@'); tableNameBase = cut < 0 ? DEFAULT_TABLE_PREFIX : metadataUrl.substring(0, cut); hbaseUrl = cut < 0 ? metadataUrl : metadataUrl.substring(cut + 1); aclTableName = tableNameBase + ACL_TABLE_NAME; fieldAces.setAccessible(true); fieldAcl.setAccessible(true); try { HBaseConnection.createHTableIfNeeded(hbaseUrl, aclTableName, ACL_INFO_FAMILY, ACL_ACES_FAMILY); } catch (IOException e) { logger.error(e.getLocalizedMessage(), e); } } @Override public List<ObjectIdentity> findChildren(ObjectIdentity parentIdentity) { List<ObjectIdentity> oids = new ArrayList<ObjectIdentity>(); HTableInterface htable = null; try { htable = HBaseConnection.get(hbaseUrl).getTable(aclTableName); Scan scan = new Scan(); SingleColumnValueFilter parentFilter = new SingleColumnValueFilter(Bytes.toBytes(ACL_INFO_FAMILY), Bytes.toBytes(ACL_INFO_FAMILY_PARENT_COLUMN), CompareOp.EQUAL, domainObjSerializer.serialize(new DomainObjectInfo(parentIdentity))); parentFilter.setFilterIfMissing(true); scan.setFilter(parentFilter); ResultScanner scanner = htable.getScanner(scan); for (Result result = scanner.next(); result != null; result = scanner.next()) { String id = Bytes.toString(result.getRow()); String type = Bytes.toString(result.getValue(Bytes.toBytes(ACL_INFO_FAMILY), Bytes.toBytes(ACL_INFO_FAMILY_TYPE_COLUMN))); oids.add(new ObjectIdentityImpl(type, id)); } } catch (IOException e) { logger.error(e.getLocalizedMessage(), e); } finally { IOUtils.closeQuietly(htable); } return oids; } @Override public Acl readAclById(ObjectIdentity object) throws NotFoundException { Map<ObjectIdentity, Acl> aclsMap = readAclsById(Arrays.asList(object), null); // Assert.isTrue(aclsMap.containsKey(object), "There should have been an Acl entry for ObjectIdentity " + object); return aclsMap.get(object); } @Override public Acl readAclById(ObjectIdentity object, List<Sid> sids) throws NotFoundException { Map<ObjectIdentity, Acl> aclsMap = readAclsById(Arrays.asList(object), sids); Assert.isTrue(aclsMap.containsKey(object), "There should have been an Acl entry for ObjectIdentity " + object); return aclsMap.get(object); } @Override public Map<ObjectIdentity, Acl> readAclsById(List<ObjectIdentity> objects) throws NotFoundException { return readAclsById(objects, null); } @Override public Map<ObjectIdentity, Acl> readAclsById(List<ObjectIdentity> oids, List<Sid> sids) throws NotFoundException { Map<ObjectIdentity, Acl> aclMaps = new HashMap<ObjectIdentity, Acl>(); HTableInterface htable = null; Result result = null; try { htable = HBaseConnection.get(hbaseUrl).getTable(aclTableName); for (ObjectIdentity oid : oids) { result = htable.get(new Get(Bytes.toBytes(String.valueOf(oid.getIdentifier())))); if (null != result && !result.isEmpty()) { SidInfo owner = sidSerializer.deserialize(result.getValue(Bytes.toBytes(ACL_INFO_FAMILY), Bytes.toBytes(ACL_INFO_FAMILY_OWNER_COLUMN))); Sid ownerSid = (null == owner) ? null : (owner.isPrincipal() ? new PrincipalSid(owner.getSid()) : new GrantedAuthoritySid(owner.getSid())); boolean entriesInheriting = Bytes.toBoolean(result.getValue(Bytes.toBytes(ACL_INFO_FAMILY), Bytes.toBytes(ACL_INFO_FAMILY_ENTRY_INHERIT_COLUMN))); Acl parentAcl = null; DomainObjectInfo parentInfo = domainObjSerializer.deserialize(result.getValue( Bytes.toBytes(ACL_INFO_FAMILY), Bytes.toBytes(ACL_INFO_FAMILY_PARENT_COLUMN))); if (null != parentInfo) { ObjectIdentity parentObj = new ObjectIdentityImpl(parentInfo.getType(), parentInfo.getId()); parentAcl = readAclById(parentObj, null); } AclImpl acl = new AclImpl(oid, oid.getIdentifier(), aclAuthorizationStrategy, permissionGrantingStrategy, parentAcl, null, entriesInheriting, ownerSid); genAces(sids, result, acl); aclMaps.put(oid, acl); } else { throw new NotFoundException("Unable to find ACL information for object identity '" + oid + "'"); } } } catch (IOException e) { logger.error(e.getLocalizedMessage(), e); } finally { IOUtils.closeQuietly(htable); } return aclMaps; } @Override public MutableAcl createAcl(ObjectIdentity objectIdentity) throws AlreadyExistsException { Acl acl = null; try { acl = readAclById(objectIdentity); } catch (NotFoundException e) { } if (null != acl) { throw new AlreadyExistsException("ACL of " + objectIdentity + " exists!"); } Authentication auth = SecurityContextHolder.getContext().getAuthentication(); PrincipalSid sid = new PrincipalSid(auth); HTableInterface htable = null; try { htable = HBaseConnection.get(hbaseUrl).getTable(aclTableName); Put put = new Put(Bytes.toBytes(String.valueOf(objectIdentity.getIdentifier()))); put.add(Bytes.toBytes(ACL_INFO_FAMILY), Bytes.toBytes(ACL_INFO_FAMILY_TYPE_COLUMN), Bytes.toBytes(objectIdentity.getType())); put.add(Bytes.toBytes(ACL_INFO_FAMILY), Bytes.toBytes(ACL_INFO_FAMILY_OWNER_COLUMN), sidSerializer.serialize(new SidInfo(sid))); put.add(Bytes.toBytes(ACL_INFO_FAMILY), Bytes.toBytes(ACL_INFO_FAMILY_ENTRY_INHERIT_COLUMN), Bytes.toBytes(true)); htable.put(put); htable.flushCommits(); logger.debug("ACL of " + objectIdentity + " created successfully."); } catch (IOException e) { logger.error(e.getLocalizedMessage(), e); } finally { IOUtils.closeQuietly(htable); } return (MutableAcl) readAclById(objectIdentity); } @Override public void deleteAcl(ObjectIdentity objectIdentity, boolean deleteChildren) throws ChildrenExistException { HTableInterface htable = null; try { htable = HBaseConnection.get(hbaseUrl).getTable(aclTableName); Delete delete = new Delete(Bytes.toBytes(String.valueOf(objectIdentity.getIdentifier()))); List<ObjectIdentity> children = findChildren(objectIdentity); if (!deleteChildren && children.size() > 0) { throw new ChildrenExistException("Children exists for " + objectIdentity); } for (ObjectIdentity oid : children) { deleteAcl(oid, deleteChildren); } htable.delete(delete); htable.flushCommits(); logger.debug("ACL of " + objectIdentity + " deleted successfully."); } catch (IOException e) { logger.error(e.getLocalizedMessage(), e); } finally { IOUtils.closeQuietly(htable); } } @Override public MutableAcl updateAcl(MutableAcl acl) throws NotFoundException { try { readAclById(acl.getObjectIdentity()); } catch (NotFoundException e) { throw e; } HTableInterface htable = null; try { htable = HBaseConnection.get(hbaseUrl).getTable(aclTableName); Delete delete = new Delete(Bytes.toBytes(String.valueOf(acl.getObjectIdentity().getIdentifier()))); delete.deleteFamily(Bytes.toBytes(ACL_ACES_FAMILY)); htable.delete(delete); Put put = new Put(Bytes.toBytes(String.valueOf(acl.getObjectIdentity().getIdentifier()))); if (null != acl.getParentAcl()) { put.add(Bytes.toBytes(ACL_INFO_FAMILY), Bytes.toBytes(ACL_INFO_FAMILY_PARENT_COLUMN), domainObjSerializer .serialize(new DomainObjectInfo(acl.getParentAcl().getObjectIdentity()))); } for (AccessControlEntry ace : acl.getEntries()) { AceInfo aceInfo = new AceInfo(ace); put.add(Bytes.toBytes(ACL_ACES_FAMILY), Bytes.toBytes(aceInfo.getSidInfo().getSid()), aceSerializer.serialize(aceInfo)); } if (!put.isEmpty()) { htable.put(put); htable.flushCommits(); logger.debug("ACL of " + acl.getObjectIdentity() + " updated successfully."); } } catch (IOException e) { logger.error(e.getLocalizedMessage(), e); } finally { IOUtils.closeQuietly(htable); } return (MutableAcl) readAclById(acl.getObjectIdentity()); } private void genAces(List<Sid> sids, Result result, AclImpl acl) { List<AceInfo> aceInfos = new ArrayList<AceInfo>(); if (null != sids) { // Just return aces in sids for (Sid sid : sids) { String sidName = null; if (sid instanceof PrincipalSid) { sidName = ((PrincipalSid) sid).getPrincipal(); } else if (sid instanceof GrantedAuthoritySid) { sidName = ((GrantedAuthoritySid) sid).getGrantedAuthority(); } AceInfo aceInfo = aceSerializer .deserialize(result.getValue(Bytes.toBytes(ACL_ACES_FAMILY), Bytes.toBytes(sidName))); if (null != aceInfo) { aceInfos.add(aceInfo); } } } else { NavigableMap<byte[], byte[]> familyMap = result.getFamilyMap(Bytes.toBytes(ACL_ACES_FAMILY)); for (byte[] qualifier : familyMap.keySet()) { AceInfo aceInfo = aceSerializer.deserialize(familyMap.get(qualifier)); if (null != aceInfo) { aceInfos.add(aceInfo); } } } List<AccessControlEntry> newAces = new ArrayList<AccessControlEntry>(); for (int i = 0; i < aceInfos.size(); i++) { AceInfo aceInfo = aceInfos.get(i); if (null != aceInfo) { Sid sid = aceInfo.getSidInfo().isPrincipal() ? new PrincipalSid(aceInfo.getSidInfo().getSid()) : new GrantedAuthoritySid(aceInfo.getSidInfo().getSid()); AccessControlEntry ace = new AccessControlEntryImpl(Long.valueOf(i), acl, sid, aclPermissionFactory.buildFromMask(aceInfo.getPermissionMask()), true, false, false); newAces.add(ace); } } this.setAces(acl, newAces); } private void setAces(AclImpl acl, List<AccessControlEntry> aces) { try { fieldAces.set(acl, aces); } catch (IllegalAccessException e) { throw new IllegalStateException("Could not set AclImpl entries", e); } } protected static class DomainObjectInfo { private String id; private String type; public DomainObjectInfo() { } public DomainObjectInfo(ObjectIdentity oid) { super(); this.id = (String) oid.getIdentifier(); this.type = oid.getType(); } public Serializable getId() { return id; } public void setId(String id) { this.id = id; } public String getType() { return type; } public void setType(String type) { this.type = type; } } protected static class SidInfo { private String sid; private boolean isPrincipal; public SidInfo() { } public SidInfo(Sid sid) { if (sid instanceof PrincipalSid) { this.sid = ((PrincipalSid) sid).getPrincipal(); this.isPrincipal = true; } else if (sid instanceof GrantedAuthoritySid) { this.sid = ((GrantedAuthoritySid) sid).getGrantedAuthority(); this.isPrincipal = false; } } public String getSid() { return sid; } public void setSid(String sid) { this.sid = sid; } public boolean isPrincipal() { return isPrincipal; } public void setPrincipal(boolean isPrincipal) { this.isPrincipal = isPrincipal; } } protected static class AceInfo { private SidInfo sidInfo; private int permissionMask; public AceInfo() { } public AceInfo(AccessControlEntry ace) { super(); this.sidInfo = new SidInfo(ace.getSid()); this.permissionMask = ace.getPermission().getMask(); } public SidInfo getSidInfo() { return sidInfo; } public void setSidInfo(SidInfo sidInfo) { this.sidInfo = sidInfo; } public int getPermissionMask() { return permissionMask; } public void setPermissionMask(int permissionMask) { this.permissionMask = permissionMask; } } }