package org.lilyproject.process.test; import com.google.common.collect.Sets; import com.ngdata.lily.security.hbase.client.AuthorizationContext; import org.apache.hadoop.hbase.KeyValue; import org.apache.hadoop.hbase.client.Get; import org.apache.hadoop.hbase.client.OperationWithAttributes; import org.apache.hadoop.hbase.client.Put; import org.apache.hadoop.hbase.coprocessor.BaseRegionObserver; import org.apache.hadoop.hbase.coprocessor.ObserverContext; import org.apache.hadoop.hbase.coprocessor.RegionCoprocessorEnvironment; import org.apache.hadoop.hbase.filter.CompareFilter; import org.apache.hadoop.hbase.filter.WritableByteArrayComparable; import org.apache.hadoop.hbase.regionserver.wal.WALEdit; import org.junit.Test; import org.lilyproject.lilyservertestfw.LilyProxy; import org.lilyproject.repository.api.LRepository; import org.lilyproject.repository.api.LTable; import org.lilyproject.repository.api.Record; import org.lilyproject.repository.api.RepositoryManager; import org.lilyproject.repository.api.TypeManager; import org.lilyproject.repository.spi.AuthorizationContextHolder; import java.io.IOException; import java.util.List; import java.util.Set; import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertNotNull; import static junit.framework.Assert.assertNull; public class AuthzTest { /** * Verifies the authorization context is properly passed on to HBase. */ @Test public void testAuthContextPassOn() throws Exception { LilyProxy lilyProxy = new LilyProxy(); System.setProperty("lily.test.hbase.coprocessor.region.classes", AuthzRegionObserver.class.getName()); lilyProxy.start(); // Set the authorization context setUser("jules", Sets.newHashSet("engineering")); // In-VM access to the repository manager (not going over the RPC interface) RepositoryManager repositoryManager = (RepositoryManager)lilyProxy.getLilyServerProxy() .getLilyServerTestingUtility().getRuntime().getJavaServiceManager() .getService(org.lilyproject.repository.api.RepositoryManager.class); // Create a record type LRepository repository = repositoryManager.getDefaultRepository(); TypeManager typeManager = repository.getTypeManager(); typeManager.recordTypeBuilder() .defaultNamespace("authztest") .name("Type1") .fieldEntry().defineField().name("field1").create().add() .fieldEntry().defineField().name("field2").create().add() .create(); assertNull(AuthzRegionObserver.lastSeenAuthzCtx); // Create a record LTable table = repository.getDefaultTable(); Record record = table.recordBuilder() .defaultNamespace("authztest") .recordType("Type1") .field("field1", "value 1") .field("field2", "value 2") .create(); assertNotNull(AuthzRegionObserver.lastSeenAuthzCtx); assertEquals("jules", AuthzRegionObserver.lastSeenAuthzCtx.getName()); // Read the record with a different user setUser("jef", Sets.newHashSet("marketing")); table.read(record.getId()); assertEquals("jef", AuthzRegionObserver.lastSeenAuthzCtx.getName()); } private void setUser(String name, Set<String> roles) { AuthorizationContext authzContext = new AuthorizationContext(name, "default", roles); AuthorizationContextHolder.setCurrentContext(authzContext); } public static class AuthzRegionObserver extends BaseRegionObserver { public static AuthorizationContext lastSeenAuthzCtx; @Override public void preGet(ObserverContext<RegionCoprocessorEnvironment> e, Get get, List<KeyValue> results) throws IOException { extractAuthzCtx(get); } @Override public void prePut(ObserverContext<RegionCoprocessorEnvironment> e, Put put, WALEdit edit, boolean writeToWAL) throws IOException { extractAuthzCtx(put); } @Override public boolean preCheckAndPut(ObserverContext<RegionCoprocessorEnvironment> e, byte[] row, byte[] family, byte[] qualifier, CompareFilter.CompareOp compareOp, WritableByteArrayComparable comparator, Put put, boolean result) throws IOException { extractAuthzCtx(put); return result; } private void extractAuthzCtx(OperationWithAttributes op) { byte[] authzCtxBytes = op.getAttribute(AuthorizationContext.OPERATION_ATTRIBUTE); if (authzCtxBytes == null) { lastSeenAuthzCtx = null; } else { lastSeenAuthzCtx = AuthorizationContext.deserialiaze(authzCtxBytes); } } } }