Java tutorial
/* * 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.accumulo.test.randomwalk.security; import static java.nio.charset.StandardCharsets.UTF_8; import java.util.Iterator; import java.util.Map.Entry; import java.util.Properties; import java.util.Random; import java.util.SortedSet; import java.util.TreeSet; import java.util.UUID; import org.apache.accumulo.core.client.AccumuloException; import org.apache.accumulo.core.client.AccumuloSecurityException; import org.apache.accumulo.core.client.BatchWriter; import org.apache.accumulo.core.client.BatchWriterConfig; import org.apache.accumulo.core.client.Connector; import org.apache.accumulo.core.client.MutationsRejectedException; import org.apache.accumulo.core.client.Scanner; import org.apache.accumulo.core.client.TableNotFoundException; import org.apache.accumulo.core.client.security.SecurityErrorCode; import org.apache.accumulo.core.conf.AccumuloConfiguration; import org.apache.accumulo.core.data.Key; import org.apache.accumulo.core.data.Mutation; import org.apache.accumulo.core.data.Value; import org.apache.accumulo.core.file.FileOperations; import org.apache.accumulo.core.file.FileSKVWriter; import org.apache.accumulo.core.file.rfile.RFile; import org.apache.accumulo.core.security.Authorizations; import org.apache.accumulo.core.security.ColumnVisibility; import org.apache.accumulo.core.security.TablePermission; import org.apache.accumulo.test.randomwalk.Environment; import org.apache.accumulo.test.randomwalk.State; import org.apache.accumulo.test.randomwalk.Test; import org.apache.hadoop.fs.FileSystem; import org.apache.hadoop.fs.Path; import org.apache.hadoop.io.Text; public class TableOp extends Test { @Override public void visit(State state, Environment env, Properties props) throws Exception { Connector conn = env.getInstance().getConnector(WalkingSecurity.get(state, env).getTabUserName(), WalkingSecurity.get(state, env).getTabToken()); String action = props.getProperty("action", "_random"); TablePermission tp; if ("_random".equalsIgnoreCase(action)) { Random r = new Random(); tp = TablePermission.values()[r.nextInt(TablePermission.values().length)]; } else { tp = TablePermission.valueOf(action); } boolean tableExists = WalkingSecurity.get(state, env).getTableExists(); String tableName = WalkingSecurity.get(state, env).getTableName(); String namespaceName = WalkingSecurity.get(state, env).getNamespaceName(); switch (tp) { case READ: { boolean canRead = WalkingSecurity.get(state, env) .canScan(WalkingSecurity.get(state, env).getTabCredentials(), tableName, namespaceName); Authorizations auths = WalkingSecurity.get(state, env) .getUserAuthorizations(WalkingSecurity.get(state, env).getTabCredentials()); boolean ambiguousZone = WalkingSecurity.get(state, env).inAmbiguousZone(conn.whoami(), tp); boolean ambiguousAuths = WalkingSecurity.get(state, env).ambiguousAuthorizations(conn.whoami()); Scanner scan = null; try { scan = conn.createScanner(tableName, conn.securityOperations().getUserAuthorizations(conn.whoami())); int seen = 0; Iterator<Entry<Key, Value>> iter = scan.iterator(); while (iter.hasNext()) { Entry<Key, Value> entry = iter.next(); Key k = entry.getKey(); seen++; if (!auths.contains(k.getColumnVisibilityData()) && !ambiguousAuths) throw new AccumuloException( "Got data I should not be capable of seeing: " + k + " table " + tableName); } if (!canRead && !ambiguousZone) throw new AccumuloException( "Was able to read when I shouldn't have had the perm with connection user " + conn.whoami() + " table " + tableName); for (Entry<String, Integer> entry : WalkingSecurity.get(state, env).getAuthsMap().entrySet()) { if (auths.contains(entry.getKey().getBytes(UTF_8))) seen = seen - entry.getValue(); } if (seen != 0 && !ambiguousAuths) throw new AccumuloException("Got mismatched amounts of data"); } catch (TableNotFoundException tnfe) { if (tableExists) throw new AccumuloException("Accumulo and test suite out of sync: table " + tableName, tnfe); return; } catch (AccumuloSecurityException ae) { if (ae.getSecurityErrorCode().equals(SecurityErrorCode.PERMISSION_DENIED)) { if (canRead && !ambiguousZone) throw new AccumuloException( "Table read permission out of sync with Accumulo: table " + tableName, ae); else return; } if (ae.getSecurityErrorCode().equals(SecurityErrorCode.BAD_AUTHORIZATIONS)) { if (ambiguousAuths) return; else throw new AccumuloException("Mismatched authorizations! ", ae); } throw new AccumuloException("Unexpected exception!", ae); } catch (RuntimeException re) { if (re.getCause() instanceof AccumuloSecurityException && ((AccumuloSecurityException) re.getCause()).getSecurityErrorCode() .equals(SecurityErrorCode.PERMISSION_DENIED)) { if (canRead && !ambiguousZone) throw new AccumuloException( "Table read permission out of sync with Accumulo: table " + tableName, re.getCause()); else return; } if (re.getCause() instanceof AccumuloSecurityException && ((AccumuloSecurityException) re.getCause()).getSecurityErrorCode() .equals(SecurityErrorCode.BAD_AUTHORIZATIONS)) { if (ambiguousAuths) return; else throw new AccumuloException("Mismatched authorizations! ", re.getCause()); } throw new AccumuloException("Unexpected exception!", re); } finally { if (scan != null) { scan.close(); scan = null; } } break; } case WRITE: boolean canWrite = WalkingSecurity.get(state, env) .canWrite(WalkingSecurity.get(state, env).getTabCredentials(), tableName, namespaceName); boolean ambiguousZone = WalkingSecurity.get(state, env).inAmbiguousZone(conn.whoami(), tp); String key = WalkingSecurity.get(state, env).getLastKey() + "1"; Mutation m = new Mutation(new Text(key)); for (String s : WalkingSecurity.get(state, env).getAuthsArray()) { m.put(new Text(), new Text(), new ColumnVisibility(s), new Value("value".getBytes(UTF_8))); } BatchWriter writer = null; try { try { writer = conn.createBatchWriter(tableName, new BatchWriterConfig().setMaxMemory(9000l).setMaxWriteThreads(1)); } catch (TableNotFoundException tnfe) { if (tableExists) throw new AccumuloException("Table didn't exist when it should have: " + tableName); return; } boolean works = true; try { writer.addMutation(m); writer.close(); } catch (MutationsRejectedException mre) { // Currently no method for detecting reason for mre. Waiting on ACCUMULO-670 // For now, just wait a second and go again if they can write! if (!canWrite) return; if (ambiguousZone) { Thread.sleep(1000); try { writer = conn.createBatchWriter(tableName, new BatchWriterConfig().setMaxWriteThreads(1)); writer.addMutation(m); writer.close(); writer = null; } catch (MutationsRejectedException mre2) { throw new AccumuloException("Mutation exception!", mre2); } } } if (works) for (String s : WalkingSecurity.get(state, env).getAuthsArray()) WalkingSecurity.get(state, env).increaseAuthMap(s, 1); } finally { if (writer != null) { writer.close(); writer = null; } } break; case BULK_IMPORT: key = WalkingSecurity.get(state, env).getLastKey() + "1"; SortedSet<Key> keys = new TreeSet<>(); for (String s : WalkingSecurity.get(state, env).getAuthsArray()) { Key k = new Key(key, "", "", s); keys.add(k); } Path dir = new Path("/tmp", "bulk_" + UUID.randomUUID().toString()); Path fail = new Path(dir.toString() + "_fail"); FileSystem fs = WalkingSecurity.get(state, env).getFs(); FileSKVWriter f = FileOperations.getInstance().newWriterBuilder() .forFile(dir + "/securityBulk." + RFile.EXTENSION, fs, fs.getConf()) .withTableConfiguration(AccumuloConfiguration.getDefaultConfiguration()).build(); f.startDefaultLocalityGroup(); fs.mkdirs(fail); for (Key k : keys) f.append(k, new Value("Value".getBytes(UTF_8))); f.close(); try { conn.tableOperations().importDirectory(tableName, dir.toString(), fail.toString(), true); } catch (TableNotFoundException tnfe) { if (tableExists) throw new AccumuloException("Table didn't exist when it should have: " + tableName); return; } catch (AccumuloSecurityException ae) { if (ae.getSecurityErrorCode().equals(SecurityErrorCode.PERMISSION_DENIED)) { if (WalkingSecurity.get(state, env).canBulkImport( WalkingSecurity.get(state, env).getTabCredentials(), tableName, namespaceName)) throw new AccumuloException("Bulk Import failed when it should have worked: " + tableName); return; } else if (ae.getSecurityErrorCode().equals(SecurityErrorCode.BAD_CREDENTIALS)) { if (WalkingSecurity.get(state, env).userPassTransient(conn.whoami())) return; } throw new AccumuloException("Unexpected exception!", ae); } for (String s : WalkingSecurity.get(state, env).getAuthsArray()) WalkingSecurity.get(state, env).increaseAuthMap(s, 1); fs.delete(dir, true); fs.delete(fail, true); if (!WalkingSecurity.get(state, env).canBulkImport(WalkingSecurity.get(state, env).getTabCredentials(), tableName, namespaceName)) throw new AccumuloException( "Bulk Import succeeded when it should have failed: " + dir + " table " + tableName); break; case ALTER_TABLE: AlterTable.renameTable(conn, state, env, tableName, tableName + "plus", WalkingSecurity.get(state, env).canAlterTable( WalkingSecurity.get(state, env).getTabCredentials(), tableName, namespaceName), tableExists); break; case GRANT: props.setProperty("task", "grant"); props.setProperty("perm", "random"); props.setProperty("source", "table"); props.setProperty("target", "system"); AlterTablePerm.alter(state, env, props); break; case DROP_TABLE: props.setProperty("source", "table"); DropTable.dropTable(state, env, props); break; } } }