You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sentry.apache.org by sp...@apache.org on 2018/05/10 00:14:35 UTC
[26/51] [partial] sentry git commit: SENTRY-2206: Refactor out sentry
api from sentry-provider-db to own module (Steve Moist,
reviewed by Sergio Pena)
http://git-wip-us.apache.org/repos/asf/sentry/blob/af8ea0ac/sentry-provider/sentry-provider-db/src/gen/thrift/gen-javabean/org/apache/sentry/service/thrift/TSentryResponseStatus.java
----------------------------------------------------------------------
diff --git a/sentry-provider/sentry-provider-db/src/gen/thrift/gen-javabean/org/apache/sentry/service/thrift/TSentryResponseStatus.java b/sentry-provider/sentry-provider-db/src/gen/thrift/gen-javabean/org/apache/sentry/service/thrift/TSentryResponseStatus.java
deleted file mode 100644
index ebd3fe3..0000000
--- a/sentry-provider/sentry-provider-db/src/gen/thrift/gen-javabean/org/apache/sentry/service/thrift/TSentryResponseStatus.java
+++ /dev/null
@@ -1,598 +0,0 @@
-/**
- * Autogenerated by Thrift Compiler (0.9.3)
- *
- * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
- * @generated
- */
-package org.apache.sentry.service.thrift;
-
-import org.apache.thrift.scheme.IScheme;
-import org.apache.thrift.scheme.SchemeFactory;
-import org.apache.thrift.scheme.StandardScheme;
-
-import org.apache.thrift.scheme.TupleScheme;
-import org.apache.thrift.protocol.TTupleProtocol;
-import org.apache.thrift.protocol.TProtocolException;
-import org.apache.thrift.EncodingUtils;
-import org.apache.thrift.TException;
-import org.apache.thrift.async.AsyncMethodCallback;
-import org.apache.thrift.server.AbstractNonblockingServer.*;
-import java.util.List;
-import java.util.ArrayList;
-import java.util.Map;
-import java.util.HashMap;
-import java.util.EnumMap;
-import java.util.Set;
-import java.util.HashSet;
-import java.util.EnumSet;
-import java.util.Collections;
-import java.util.BitSet;
-import java.nio.ByteBuffer;
-import java.util.Arrays;
-import javax.annotation.Generated;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-@SuppressWarnings({"cast", "rawtypes", "serial", "unchecked"})
-@Generated(value = "Autogenerated by Thrift Compiler (0.9.3)")
-public class TSentryResponseStatus implements org.apache.thrift.TBase<TSentryResponseStatus, TSentryResponseStatus._Fields>, java.io.Serializable, Cloneable, Comparable<TSentryResponseStatus> {
- private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("TSentryResponseStatus");
-
- private static final org.apache.thrift.protocol.TField VALUE_FIELD_DESC = new org.apache.thrift.protocol.TField("value", org.apache.thrift.protocol.TType.I32, (short)1);
- private static final org.apache.thrift.protocol.TField MESSAGE_FIELD_DESC = new org.apache.thrift.protocol.TField("message", org.apache.thrift.protocol.TType.STRING, (short)2);
- private static final org.apache.thrift.protocol.TField STACK_FIELD_DESC = new org.apache.thrift.protocol.TField("stack", org.apache.thrift.protocol.TType.STRING, (short)3);
-
- private static final Map<Class<? extends IScheme>, SchemeFactory> schemes = new HashMap<Class<? extends IScheme>, SchemeFactory>();
- static {
- schemes.put(StandardScheme.class, new TSentryResponseStatusStandardSchemeFactory());
- schemes.put(TupleScheme.class, new TSentryResponseStatusTupleSchemeFactory());
- }
-
- private int value; // required
- private String message; // required
- private String stack; // optional
-
- /** The set of fields this struct contains, along with convenience methods for finding and manipulating them. */
- public enum _Fields implements org.apache.thrift.TFieldIdEnum {
- VALUE((short)1, "value"),
- MESSAGE((short)2, "message"),
- STACK((short)3, "stack");
-
- private static final Map<String, _Fields> byName = new HashMap<String, _Fields>();
-
- static {
- for (_Fields field : EnumSet.allOf(_Fields.class)) {
- byName.put(field.getFieldName(), field);
- }
- }
-
- /**
- * Find the _Fields constant that matches fieldId, or null if its not found.
- */
- public static _Fields findByThriftId(int fieldId) {
- switch(fieldId) {
- case 1: // VALUE
- return VALUE;
- case 2: // MESSAGE
- return MESSAGE;
- case 3: // STACK
- return STACK;
- default:
- return null;
- }
- }
-
- /**
- * Find the _Fields constant that matches fieldId, throwing an exception
- * if it is not found.
- */
- public static _Fields findByThriftIdOrThrow(int fieldId) {
- _Fields fields = findByThriftId(fieldId);
- if (fields == null) throw new IllegalArgumentException("Field " + fieldId + " doesn't exist!");
- return fields;
- }
-
- /**
- * Find the _Fields constant that matches name, or null if its not found.
- */
- public static _Fields findByName(String name) {
- return byName.get(name);
- }
-
- private final short _thriftId;
- private final String _fieldName;
-
- _Fields(short thriftId, String fieldName) {
- _thriftId = thriftId;
- _fieldName = fieldName;
- }
-
- public short getThriftFieldId() {
- return _thriftId;
- }
-
- public String getFieldName() {
- return _fieldName;
- }
- }
-
- // isset id assignments
- private static final int __VALUE_ISSET_ID = 0;
- private byte __isset_bitfield = 0;
- private static final _Fields optionals[] = {_Fields.STACK};
- public static final Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> metaDataMap;
- static {
- Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> tmpMap = new EnumMap<_Fields, org.apache.thrift.meta_data.FieldMetaData>(_Fields.class);
- tmpMap.put(_Fields.VALUE, new org.apache.thrift.meta_data.FieldMetaData("value", org.apache.thrift.TFieldRequirementType.REQUIRED,
- new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.I32)));
- tmpMap.put(_Fields.MESSAGE, new org.apache.thrift.meta_data.FieldMetaData("message", org.apache.thrift.TFieldRequirementType.REQUIRED,
- new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.STRING)));
- tmpMap.put(_Fields.STACK, new org.apache.thrift.meta_data.FieldMetaData("stack", org.apache.thrift.TFieldRequirementType.OPTIONAL,
- new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.STRING)));
- metaDataMap = Collections.unmodifiableMap(tmpMap);
- org.apache.thrift.meta_data.FieldMetaData.addStructMetaDataMap(TSentryResponseStatus.class, metaDataMap);
- }
-
- public TSentryResponseStatus() {
- }
-
- public TSentryResponseStatus(
- int value,
- String message)
- {
- this();
- this.value = value;
- setValueIsSet(true);
- this.message = message;
- }
-
- /**
- * Performs a deep copy on <i>other</i>.
- */
- public TSentryResponseStatus(TSentryResponseStatus other) {
- __isset_bitfield = other.__isset_bitfield;
- this.value = other.value;
- if (other.isSetMessage()) {
- this.message = other.message;
- }
- if (other.isSetStack()) {
- this.stack = other.stack;
- }
- }
-
- public TSentryResponseStatus deepCopy() {
- return new TSentryResponseStatus(this);
- }
-
- @Override
- public void clear() {
- setValueIsSet(false);
- this.value = 0;
- this.message = null;
- this.stack = null;
- }
-
- public int getValue() {
- return this.value;
- }
-
- public void setValue(int value) {
- this.value = value;
- setValueIsSet(true);
- }
-
- public void unsetValue() {
- __isset_bitfield = EncodingUtils.clearBit(__isset_bitfield, __VALUE_ISSET_ID);
- }
-
- /** Returns true if field value is set (has been assigned a value) and false otherwise */
- public boolean isSetValue() {
- return EncodingUtils.testBit(__isset_bitfield, __VALUE_ISSET_ID);
- }
-
- public void setValueIsSet(boolean value) {
- __isset_bitfield = EncodingUtils.setBit(__isset_bitfield, __VALUE_ISSET_ID, value);
- }
-
- public String getMessage() {
- return this.message;
- }
-
- public void setMessage(String message) {
- this.message = message;
- }
-
- public void unsetMessage() {
- this.message = null;
- }
-
- /** Returns true if field message is set (has been assigned a value) and false otherwise */
- public boolean isSetMessage() {
- return this.message != null;
- }
-
- public void setMessageIsSet(boolean value) {
- if (!value) {
- this.message = null;
- }
- }
-
- public String getStack() {
- return this.stack;
- }
-
- public void setStack(String stack) {
- this.stack = stack;
- }
-
- public void unsetStack() {
- this.stack = null;
- }
-
- /** Returns true if field stack is set (has been assigned a value) and false otherwise */
- public boolean isSetStack() {
- return this.stack != null;
- }
-
- public void setStackIsSet(boolean value) {
- if (!value) {
- this.stack = null;
- }
- }
-
- public void setFieldValue(_Fields field, Object value) {
- switch (field) {
- case VALUE:
- if (value == null) {
- unsetValue();
- } else {
- setValue((Integer)value);
- }
- break;
-
- case MESSAGE:
- if (value == null) {
- unsetMessage();
- } else {
- setMessage((String)value);
- }
- break;
-
- case STACK:
- if (value == null) {
- unsetStack();
- } else {
- setStack((String)value);
- }
- break;
-
- }
- }
-
- public Object getFieldValue(_Fields field) {
- switch (field) {
- case VALUE:
- return getValue();
-
- case MESSAGE:
- return getMessage();
-
- case STACK:
- return getStack();
-
- }
- throw new IllegalStateException();
- }
-
- /** Returns true if field corresponding to fieldID is set (has been assigned a value) and false otherwise */
- public boolean isSet(_Fields field) {
- if (field == null) {
- throw new IllegalArgumentException();
- }
-
- switch (field) {
- case VALUE:
- return isSetValue();
- case MESSAGE:
- return isSetMessage();
- case STACK:
- return isSetStack();
- }
- throw new IllegalStateException();
- }
-
- @Override
- public boolean equals(Object that) {
- if (that == null)
- return false;
- if (that instanceof TSentryResponseStatus)
- return this.equals((TSentryResponseStatus)that);
- return false;
- }
-
- public boolean equals(TSentryResponseStatus that) {
- if (that == null)
- return false;
-
- boolean this_present_value = true;
- boolean that_present_value = true;
- if (this_present_value || that_present_value) {
- if (!(this_present_value && that_present_value))
- return false;
- if (this.value != that.value)
- return false;
- }
-
- boolean this_present_message = true && this.isSetMessage();
- boolean that_present_message = true && that.isSetMessage();
- if (this_present_message || that_present_message) {
- if (!(this_present_message && that_present_message))
- return false;
- if (!this.message.equals(that.message))
- return false;
- }
-
- boolean this_present_stack = true && this.isSetStack();
- boolean that_present_stack = true && that.isSetStack();
- if (this_present_stack || that_present_stack) {
- if (!(this_present_stack && that_present_stack))
- return false;
- if (!this.stack.equals(that.stack))
- return false;
- }
-
- return true;
- }
-
- @Override
- public int hashCode() {
- List<Object> list = new ArrayList<Object>();
-
- boolean present_value = true;
- list.add(present_value);
- if (present_value)
- list.add(value);
-
- boolean present_message = true && (isSetMessage());
- list.add(present_message);
- if (present_message)
- list.add(message);
-
- boolean present_stack = true && (isSetStack());
- list.add(present_stack);
- if (present_stack)
- list.add(stack);
-
- return list.hashCode();
- }
-
- @Override
- public int compareTo(TSentryResponseStatus other) {
- if (!getClass().equals(other.getClass())) {
- return getClass().getName().compareTo(other.getClass().getName());
- }
-
- int lastComparison = 0;
-
- lastComparison = Boolean.valueOf(isSetValue()).compareTo(other.isSetValue());
- if (lastComparison != 0) {
- return lastComparison;
- }
- if (isSetValue()) {
- lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.value, other.value);
- if (lastComparison != 0) {
- return lastComparison;
- }
- }
- lastComparison = Boolean.valueOf(isSetMessage()).compareTo(other.isSetMessage());
- if (lastComparison != 0) {
- return lastComparison;
- }
- if (isSetMessage()) {
- lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.message, other.message);
- if (lastComparison != 0) {
- return lastComparison;
- }
- }
- lastComparison = Boolean.valueOf(isSetStack()).compareTo(other.isSetStack());
- if (lastComparison != 0) {
- return lastComparison;
- }
- if (isSetStack()) {
- lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.stack, other.stack);
- if (lastComparison != 0) {
- return lastComparison;
- }
- }
- return 0;
- }
-
- public _Fields fieldForId(int fieldId) {
- return _Fields.findByThriftId(fieldId);
- }
-
- public void read(org.apache.thrift.protocol.TProtocol iprot) throws org.apache.thrift.TException {
- schemes.get(iprot.getScheme()).getScheme().read(iprot, this);
- }
-
- public void write(org.apache.thrift.protocol.TProtocol oprot) throws org.apache.thrift.TException {
- schemes.get(oprot.getScheme()).getScheme().write(oprot, this);
- }
-
- @Override
- public String toString() {
- StringBuilder sb = new StringBuilder("TSentryResponseStatus(");
- boolean first = true;
-
- sb.append("value:");
- sb.append(this.value);
- first = false;
- if (!first) sb.append(", ");
- sb.append("message:");
- if (this.message == null) {
- sb.append("null");
- } else {
- sb.append(this.message);
- }
- first = false;
- if (isSetStack()) {
- if (!first) sb.append(", ");
- sb.append("stack:");
- if (this.stack == null) {
- sb.append("null");
- } else {
- sb.append(this.stack);
- }
- first = false;
- }
- sb.append(")");
- return sb.toString();
- }
-
- public void validate() throws org.apache.thrift.TException {
- // check for required fields
- if (!isSetValue()) {
- throw new org.apache.thrift.protocol.TProtocolException("Required field 'value' is unset! Struct:" + toString());
- }
-
- if (!isSetMessage()) {
- throw new org.apache.thrift.protocol.TProtocolException("Required field 'message' is unset! Struct:" + toString());
- }
-
- // check for sub-struct validity
- }
-
- private void writeObject(java.io.ObjectOutputStream out) throws java.io.IOException {
- try {
- write(new org.apache.thrift.protocol.TCompactProtocol(new org.apache.thrift.transport.TIOStreamTransport(out)));
- } catch (org.apache.thrift.TException te) {
- throw new java.io.IOException(te);
- }
- }
-
- private void readObject(java.io.ObjectInputStream in) throws java.io.IOException, ClassNotFoundException {
- try {
- // it doesn't seem like you should have to do this, but java serialization is wacky, and doesn't call the default constructor.
- __isset_bitfield = 0;
- read(new org.apache.thrift.protocol.TCompactProtocol(new org.apache.thrift.transport.TIOStreamTransport(in)));
- } catch (org.apache.thrift.TException te) {
- throw new java.io.IOException(te);
- }
- }
-
- private static class TSentryResponseStatusStandardSchemeFactory implements SchemeFactory {
- public TSentryResponseStatusStandardScheme getScheme() {
- return new TSentryResponseStatusStandardScheme();
- }
- }
-
- private static class TSentryResponseStatusStandardScheme extends StandardScheme<TSentryResponseStatus> {
-
- public void read(org.apache.thrift.protocol.TProtocol iprot, TSentryResponseStatus struct) throws org.apache.thrift.TException {
- org.apache.thrift.protocol.TField schemeField;
- iprot.readStructBegin();
- while (true)
- {
- schemeField = iprot.readFieldBegin();
- if (schemeField.type == org.apache.thrift.protocol.TType.STOP) {
- break;
- }
- switch (schemeField.id) {
- case 1: // VALUE
- if (schemeField.type == org.apache.thrift.protocol.TType.I32) {
- struct.value = iprot.readI32();
- struct.setValueIsSet(true);
- } else {
- org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type);
- }
- break;
- case 2: // MESSAGE
- if (schemeField.type == org.apache.thrift.protocol.TType.STRING) {
- struct.message = iprot.readString();
- struct.setMessageIsSet(true);
- } else {
- org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type);
- }
- break;
- case 3: // STACK
- if (schemeField.type == org.apache.thrift.protocol.TType.STRING) {
- struct.stack = iprot.readString();
- struct.setStackIsSet(true);
- } else {
- org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type);
- }
- break;
- default:
- org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type);
- }
- iprot.readFieldEnd();
- }
- iprot.readStructEnd();
- struct.validate();
- }
-
- public void write(org.apache.thrift.protocol.TProtocol oprot, TSentryResponseStatus struct) throws org.apache.thrift.TException {
- struct.validate();
-
- oprot.writeStructBegin(STRUCT_DESC);
- oprot.writeFieldBegin(VALUE_FIELD_DESC);
- oprot.writeI32(struct.value);
- oprot.writeFieldEnd();
- if (struct.message != null) {
- oprot.writeFieldBegin(MESSAGE_FIELD_DESC);
- oprot.writeString(struct.message);
- oprot.writeFieldEnd();
- }
- if (struct.stack != null) {
- if (struct.isSetStack()) {
- oprot.writeFieldBegin(STACK_FIELD_DESC);
- oprot.writeString(struct.stack);
- oprot.writeFieldEnd();
- }
- }
- oprot.writeFieldStop();
- oprot.writeStructEnd();
- }
-
- }
-
- private static class TSentryResponseStatusTupleSchemeFactory implements SchemeFactory {
- public TSentryResponseStatusTupleScheme getScheme() {
- return new TSentryResponseStatusTupleScheme();
- }
- }
-
- private static class TSentryResponseStatusTupleScheme extends TupleScheme<TSentryResponseStatus> {
-
- @Override
- public void write(org.apache.thrift.protocol.TProtocol prot, TSentryResponseStatus struct) throws org.apache.thrift.TException {
- TTupleProtocol oprot = (TTupleProtocol) prot;
- oprot.writeI32(struct.value);
- oprot.writeString(struct.message);
- BitSet optionals = new BitSet();
- if (struct.isSetStack()) {
- optionals.set(0);
- }
- oprot.writeBitSet(optionals, 1);
- if (struct.isSetStack()) {
- oprot.writeString(struct.stack);
- }
- }
-
- @Override
- public void read(org.apache.thrift.protocol.TProtocol prot, TSentryResponseStatus struct) throws org.apache.thrift.TException {
- TTupleProtocol iprot = (TTupleProtocol) prot;
- struct.value = iprot.readI32();
- struct.setValueIsSet(true);
- struct.message = iprot.readString();
- struct.setMessageIsSet(true);
- BitSet incoming = iprot.readBitSet(1);
- if (incoming.get(0)) {
- struct.stack = iprot.readString();
- struct.setStackIsSet(true);
- }
- }
- }
-
-}
-
http://git-wip-us.apache.org/repos/asf/sentry/blob/af8ea0ac/sentry-provider/sentry-provider-db/src/gen/thrift/gen-javabean/org/apache/sentry/service/thrift/sentry_common_serviceConstants.java
----------------------------------------------------------------------
diff --git a/sentry-provider/sentry-provider-db/src/gen/thrift/gen-javabean/org/apache/sentry/service/thrift/sentry_common_serviceConstants.java b/sentry-provider/sentry-provider-db/src/gen/thrift/gen-javabean/org/apache/sentry/service/thrift/sentry_common_serviceConstants.java
deleted file mode 100644
index eb63bc3..0000000
--- a/sentry-provider/sentry-provider-db/src/gen/thrift/gen-javabean/org/apache/sentry/service/thrift/sentry_common_serviceConstants.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/**
- * Autogenerated by Thrift Compiler (0.9.3)
- *
- * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
- * @generated
- */
-package org.apache.sentry.service.thrift;
-
-import org.apache.thrift.scheme.IScheme;
-import org.apache.thrift.scheme.SchemeFactory;
-import org.apache.thrift.scheme.StandardScheme;
-
-import org.apache.thrift.scheme.TupleScheme;
-import org.apache.thrift.protocol.TTupleProtocol;
-import org.apache.thrift.protocol.TProtocolException;
-import org.apache.thrift.EncodingUtils;
-import org.apache.thrift.TException;
-import org.apache.thrift.async.AsyncMethodCallback;
-import org.apache.thrift.server.AbstractNonblockingServer.*;
-import java.util.List;
-import java.util.ArrayList;
-import java.util.Map;
-import java.util.HashMap;
-import java.util.EnumMap;
-import java.util.Set;
-import java.util.HashSet;
-import java.util.EnumSet;
-import java.util.Collections;
-import java.util.BitSet;
-import java.nio.ByteBuffer;
-import java.util.Arrays;
-import javax.annotation.Generated;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-@SuppressWarnings({"cast", "rawtypes", "serial", "unchecked"})
-public class sentry_common_serviceConstants {
-
- public static final int TSENTRY_SERVICE_V1 = 1;
-
- public static final int TSENTRY_SERVICE_V2 = 2;
-
- public static final int TSENTRY_STATUS_OK = 0;
-
- public static final int TSENTRY_STATUS_ALREADY_EXISTS = 1;
-
- public static final int TSENTRY_STATUS_NO_SUCH_OBJECT = 2;
-
- public static final int TSENTRY_STATUS_RUNTIME_ERROR = 3;
-
- public static final int TSENTRY_STATUS_INVALID_INPUT = 4;
-
- public static final int TSENTRY_STATUS_ACCESS_DENIED = 5;
-
- public static final int TSENTRY_STATUS_THRIFT_VERSION_MISMATCH = 6;
-
-}
http://git-wip-us.apache.org/repos/asf/sentry/blob/af8ea0ac/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/api/generic/thrift/SentryGenericPolicyProcessor.java
----------------------------------------------------------------------
diff --git a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/api/generic/thrift/SentryGenericPolicyProcessor.java b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/api/generic/thrift/SentryGenericPolicyProcessor.java
new file mode 100644
index 0000000..1cc4b1b
--- /dev/null
+++ b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/api/generic/thrift/SentryGenericPolicyProcessor.java
@@ -0,0 +1,829 @@
+/**
+ * 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.sentry.api.generic.thrift;
+
+import static org.apache.sentry.core.common.utils.SentryConstants.AUTHORIZABLE_JOINER;
+import static org.apache.sentry.core.common.utils.SentryConstants.KV_JOINER;
+
+import java.lang.reflect.Constructor;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.hadoop.conf.Configuration;
+import org.apache.sentry.api.common.ThriftConstants;
+import org.apache.sentry.core.common.exception.SentryUserException;
+import org.apache.sentry.core.common.Authorizable;
+import org.apache.sentry.core.common.utils.SentryConstants;
+import org.apache.sentry.core.common.exception.SentrySiteConfigurationException;
+import org.apache.sentry.core.model.db.AccessConstants;
+import org.apache.sentry.core.common.utils.KeyValue;
+import org.apache.sentry.provider.common.AuthorizationComponent;
+import org.apache.sentry.core.common.exception.SentryAccessDeniedException;
+import org.apache.sentry.core.common.exception.SentryAlreadyExistsException;
+import org.apache.sentry.core.common.exception.SentryInvalidInputException;
+import org.apache.sentry.core.common.exception.SentryNoSuchObjectException;
+import org.apache.sentry.core.common.exception.SentryThriftAPIMismatchException;
+import org.apache.sentry.provider.db.generic.service.persistent.DelegateSentryStore;
+import org.apache.sentry.provider.db.generic.service.persistent.PrivilegeObject;
+import org.apache.sentry.provider.db.generic.service.persistent.PrivilegeObject.Builder;
+import org.apache.sentry.provider.db.generic.service.persistent.SentryStoreLayer;
+import org.apache.sentry.provider.db.log.entity.JsonLogEntityFactory;
+import org.apache.sentry.provider.db.log.util.Constants;
+import org.apache.sentry.provider.db.service.model.MSentryGMPrivilege;
+import org.apache.sentry.provider.db.service.model.MSentryRole;
+import org.apache.sentry.core.common.utils.PolicyStoreConstants;
+import org.apache.sentry.api.service.thrift.SentryPolicyStoreProcessor;
+import org.apache.sentry.service.common.ServiceConstants.ServerConfig;
+import org.apache.sentry.api.common.Status;
+import org.apache.sentry.service.thrift.TSentryResponseStatus;
+import org.apache.thrift.TException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Splitter;
+import com.google.common.base.Strings;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
+
+public class SentryGenericPolicyProcessor implements SentryGenericPolicyService.Iface {
+ private static final Logger LOGGER = LoggerFactory.getLogger(SentryGenericPolicyProcessor.class);
+ private static final Logger AUDIT_LOGGER = LoggerFactory
+ .getLogger(Constants.AUDIT_LOGGER_NAME_GENERIC);
+ private final Configuration conf;
+ private final ImmutableSet<String> adminGroups;
+ private final SentryStoreLayer store;
+ private final NotificationHandlerInvoker handerInvoker;
+
+ private static final String ACCESS_DENIAL_MESSAGE = "Access denied to ";
+
+ SentryGenericPolicyProcessor(Configuration conf) throws Exception {
+ this.store = new DelegateSentryStore(conf);
+ this.handerInvoker = new NotificationHandlerInvoker(createHandlers(conf));
+ this.conf = conf;
+ adminGroups = ImmutableSet.copyOf((Sets.newHashSet(conf.getStrings(
+ ServerConfig.ADMIN_GROUPS, new String[]{}))));
+ }
+
+ @VisibleForTesting
+ SentryGenericPolicyProcessor(Configuration conf, SentryStoreLayer store) throws Exception {
+ this.store = store;
+ this.handerInvoker = new NotificationHandlerInvoker(createHandlers(conf));
+ this.conf = conf;
+ adminGroups = ImmutableSet.copyOf(toTrimmed(Sets.newHashSet(conf.getStrings(
+ ServerConfig.ADMIN_GROUPS, new String[]{}))));
+ }
+
+ private void authorize(String requestorUser, Set<String> requestorGroups)
+ throws SentryAccessDeniedException {
+ if (!inAdminGroups(requestorGroups)) {
+ String msg = "User: " + requestorUser + " is part of " + requestorGroups +
+ " which does not, intersect admin groups " + adminGroups;
+ LOGGER.warn(msg);
+ throw new SentryAccessDeniedException(ACCESS_DENIAL_MESSAGE + requestorUser);
+ }
+ }
+
+ private Set<String> toTrimmedLower(Set<String> s) {
+ if (s == null) {
+ return Collections.emptySet();
+ }
+ Set<String> result = new HashSet<>(s.size());
+ for (String v : s) {
+ result.add(v.trim().toLowerCase());
+ }
+ return result;
+ }
+
+ private Set<String> toTrimmed(Set<String> s) {
+ if (s == null) {
+ return Collections.emptySet();
+ }
+ Set<String> result = new HashSet<>(s.size());
+ for (String v : s) {
+ result.add(v.trim());
+ }
+ return result;
+ }
+
+ private String toTrimmedLower(String s) {
+ if (Strings.isNullOrEmpty(s)){
+ return "";
+ }
+ return s.trim().toLowerCase();
+ }
+
+ private static Set<String> getRequestorGroups(Configuration conf, String userName) throws SentryUserException {
+ return SentryPolicyStoreProcessor.getGroupsFromUserName(conf, userName);
+ }
+
+ private boolean inAdminGroups(Set<String> requestorGroups) {
+ return !Sets.intersection(adminGroups, requestorGroups).isEmpty();
+ }
+
+ static List<NotificationHandler> createHandlers(Configuration conf) throws SentrySiteConfigurationException {
+
+ List<NotificationHandler> handlers = Lists.newArrayList();
+ Iterable<String> notificationHandlers = Splitter.onPattern("[\\s,]").trimResults()
+ .omitEmptyStrings().split(conf.get(PolicyStoreConstants.SENTRY_GENERIC_POLICY_NOTIFICATION, ""));
+ try {
+ for (String notificationHandler : notificationHandlers) {
+ handlers.add(createInstance(notificationHandler, conf, NotificationHandler.class));
+ }
+ } catch (Exception e) {
+ throw new SentrySiteConfigurationException("Create notificationHandlers error: " + e.getMessage(), e);
+ }
+ return handlers;
+ }
+
+ @SuppressWarnings("unchecked")
+ private static <T> T createInstance(String className, Configuration conf, Class<T> iface) throws Exception {
+ T result;
+ try {
+ Class<?> clazz = Class.forName(className);
+ if (!iface.isAssignableFrom(clazz)) {
+ throw new IllegalArgumentException("Class " + clazz + " is not a " +
+ iface.getName());
+ }
+ Constructor<T> meth = (Constructor<T>)clazz.getDeclaredConstructor(Configuration.class);
+ meth.setAccessible(true);
+ result = meth.newInstance(new Object[]{conf});
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ return result;
+ }
+
+ private <T> Response<T> requestHandle(RequestHandler<T> handler) {
+ Response<T> response = new Response<T>();
+ try {
+ response = handler.handle();
+ } catch (SentryAccessDeniedException e) {
+ String msg = "Sentry access denied: " + e.getMessage();
+ LOGGER.error(msg, e);
+ response.status = Status.AccessDenied(e.getMessage(), e);
+ } catch (SentryAlreadyExistsException e) {
+ String msg = "Sentry object already exists: " + e.getMessage();
+ LOGGER.error(msg, e);
+ response.status = Status.AlreadyExists(e.getMessage(), e);
+ } catch (SentryNoSuchObjectException e) {
+ String msg = "Sentry object doesn't exist: " + e.getMessage();
+ LOGGER.error(msg, e);
+ response.status = Status.NoSuchObject(e.getMessage(), e);
+ } catch (SentryInvalidInputException e) {
+ String msg = "Invalid input privilege object: " + e.getMessage();
+ LOGGER.error(msg, e);
+ response.status = Status.InvalidInput(msg, e);
+ } catch (SentryThriftAPIMismatchException e) {
+ String msg = "Sentry thrift API mismatch error: " + e.getMessage();
+ LOGGER.error(msg, e);
+ response.status = Status.THRIFT_VERSION_MISMATCH(e.getMessage(), e);
+ } catch (Exception e) {
+ String msg = "Unknown error:" + e.getMessage();
+ LOGGER.error(msg, e);
+ response.status = Status.RuntimeError(msg, e);
+ }
+ return response;
+ }
+
+ private PrivilegeObject toPrivilegeObject(TSentryPrivilege tSentryPrivilege) {
+ Boolean grantOption;
+ if (tSentryPrivilege.getGrantOption().equals(TSentryGrantOption.TRUE)) {
+ grantOption = true;
+ } else if (tSentryPrivilege.getGrantOption().equals(TSentryGrantOption.FALSE)) {
+ grantOption = false;
+ } else {
+ grantOption = null;
+ }
+ return new Builder().setComponent(tSentryPrivilege.getComponent())
+ .setService(tSentryPrivilege.getServiceName())
+ .setAuthorizables(toAuthorizables(tSentryPrivilege.getAuthorizables()))
+ .setAction(tSentryPrivilege.getAction())
+ .withGrantOption(grantOption)
+ .build();
+ }
+
+ private TSentryPrivilege fromPrivilegeObject(PrivilegeObject privilege) {
+
+ TSentryPrivilege tPrivilege = new TSentryPrivilege(privilege.getComponent(), privilege.getService(),
+ fromAuthorizable(privilege.getAuthorizables()),
+ privilege.getAction());
+ if (privilege.getGrantOption() == null) {
+ tPrivilege.setGrantOption(TSentryGrantOption.UNSET);
+ } else if (privilege.getGrantOption()) {
+ tPrivilege.setGrantOption(TSentryGrantOption.TRUE);
+ } else {
+ tPrivilege.setGrantOption(TSentryGrantOption.FALSE);
+ }
+ return tPrivilege;
+ }
+
+ private List<TAuthorizable> fromAuthorizable(List<? extends Authorizable> authorizables) {
+ List<TAuthorizable> tAuthorizables = Lists.newArrayList();
+ for (Authorizable authorizable : authorizables) {
+ tAuthorizables.add(new TAuthorizable(authorizable.getTypeName(), authorizable.getName()));
+ }
+ return tAuthorizables;
+ }
+
+ private String fromAuthorizableToStr(List<? extends Authorizable> authorizables) {
+ if (authorizables != null && !authorizables.isEmpty()) {
+ List<String> privileges = Lists.newArrayList();
+
+ for (Authorizable authorizable : authorizables) {
+
+ privileges.add(SentryConstants.KV_JOINER.join(authorizable.getTypeName(),
+ authorizable.getName()));
+ }
+
+ return SentryConstants.AUTHORIZABLE_JOINER.join(privileges);
+ } else {
+ return "";
+ }
+ }
+
+ private List<? extends Authorizable> toAuthorizables(List<TAuthorizable> tAuthorizables) {
+ List<Authorizable> authorizables = Lists.newArrayList();
+ if (tAuthorizables == null) {
+ return authorizables;
+ }
+ for (final TAuthorizable tAuthorizable : tAuthorizables) {
+ authorizables.add(new Authorizable() {
+ @Override
+ public String getTypeName() {
+ return tAuthorizable.getType();
+ }
+ @Override
+ public String getName() {
+ return tAuthorizable.getName();
+ }
+ });
+ }
+ return authorizables;
+ }
+
+ private List<? extends Authorizable> toAuthorizables(String privilegeStr) {
+ List<Authorizable> authorizables = Lists.newArrayList();
+ if (privilegeStr == null) {
+ return authorizables;
+ }
+
+ for (String authorizable : SentryConstants.AUTHORIZABLE_SPLITTER.split(privilegeStr)) {
+ KeyValue tempKV = new KeyValue(authorizable);
+ final String key = tempKV.getKey();
+ final String value = tempKV.getValue();
+
+ authorizables.add(new Authorizable() {
+ @Override
+ public String getTypeName() {
+ return key;
+ }
+
+ @Override
+ public String getName() {
+ return value;
+ }
+ });
+ }
+
+ return authorizables;
+ }
+
+ // Construct the role to set of privileges mapping based on the
+ // MSentryGMPrivilege information.
+ private TSentryPrivilegeMap toTSentryPrivilegeMap(Set<MSentryGMPrivilege> mPrivileges) {
+
+ // Mapping of <Role, Set<Privilege>>.
+ Map<String, Set<TSentryPrivilege>> tPrivilegeMap = Maps.newTreeMap();
+
+ for (MSentryGMPrivilege mPrivilege : mPrivileges) {
+ for (MSentryRole role : mPrivilege.getRoles()) {
+
+ TSentryPrivilege tPrivilege = toTSentryPrivilege(mPrivilege);
+
+ if (tPrivilegeMap.containsKey(role.getRoleName())) {
+ tPrivilegeMap.get(role.getRoleName()).add(tPrivilege);
+ } else {
+ Set<TSentryPrivilege> tPrivilegeSet = Sets.newTreeSet();
+ tPrivilegeSet.add(tPrivilege);
+ tPrivilegeMap.put(role.getRoleName(), tPrivilegeSet);
+ }
+ }
+ }
+
+ return new TSentryPrivilegeMap(tPrivilegeMap);
+ }
+
+ // Construct TSentryPrivilege based on MSentryGMPrivilege information.
+ private TSentryPrivilege toTSentryPrivilege(MSentryGMPrivilege mPrivilege) {
+
+ TSentryPrivilege tPrivilege = new TSentryPrivilege(mPrivilege.getComponentName(),
+ mPrivilege.getServiceName(), fromAuthorizable(mPrivilege.getAuthorizables()), mPrivilege.getAction());
+
+ if (mPrivilege.getGrantOption() == null) {
+ tPrivilege.setGrantOption(TSentryGrantOption.UNSET);
+ } else if (mPrivilege.getGrantOption()) {
+ tPrivilege.setGrantOption(TSentryGrantOption.TRUE);
+ } else {
+ tPrivilege.setGrantOption(TSentryGrantOption.FALSE);
+ }
+
+ return tPrivilege;
+ }
+
+ private Set<String> buildPermissions(Set<PrivilegeObject> privileges) {
+ Set<String> permissions = Sets.newHashSet();
+ for (PrivilegeObject privilege : privileges) {
+ List<String> hierarchy = Lists.newArrayList();
+ if (hasComponentServerPrivilege(privilege.getComponent())) {
+ hierarchy.add(KV_JOINER.join("server", privilege.getService()));
+ }
+ for (Authorizable authorizable : privilege.getAuthorizables()) {
+ hierarchy.add(KV_JOINER.join(authorizable.getTypeName(),authorizable.getName()));
+ }
+ hierarchy.add(KV_JOINER.join("action", privilege.getAction()));
+ permissions.add(AUTHORIZABLE_JOINER.join(hierarchy));
+ }
+ return permissions;
+ }
+
+ private boolean hasComponentServerPrivilege(String component) {
+ //judge the component whether has the server privilege, for example: sqoop has the privilege on the server
+ return AuthorizationComponent.SQOOP.equalsIgnoreCase(component);
+ }
+
+ @Override
+ public TCreateSentryRoleResponse create_sentry_role(
+ final TCreateSentryRoleRequest request) throws TException {
+ Response<Void> respose = requestHandle(new RequestHandler<Void>() {
+ @Override
+ public Response<Void> handle() throws Exception {
+ validateClientVersion(request.getProtocol_version());
+ authorize(request.getRequestorUserName(),
+ getRequestorGroups(conf, request.getRequestorUserName()));
+ store.createRole(request.getComponent(), request.getRoleName(),
+ request.getRequestorUserName());
+ return new Response<Void>(Status.OK());
+ }
+ });
+
+ TCreateSentryRoleResponse tResponse = new TCreateSentryRoleResponse(respose.status);
+ if (Status.OK.getCode() == respose.status.getValue()) {
+ handerInvoker.create_sentry_role(request, tResponse);
+ }
+
+ try {
+ AUDIT_LOGGER.info(JsonLogEntityFactory.getInstance()
+ .createJsonLogEntity(request, tResponse, conf).toJsonFormatLog());
+ } catch (Exception e) {
+ // if any exception, log the exception.
+ String msg = "Error in creating audit log for create role: " + e.getMessage();
+ LOGGER.error(msg, e);
+ }
+ return tResponse;
+ }
+
+ @Override
+ public TDropSentryRoleResponse drop_sentry_role(final TDropSentryRoleRequest request)
+ throws TException {
+ Response<Void> respose = requestHandle(new RequestHandler<Void>() {
+ @Override
+ public Response<Void> handle() throws Exception {
+ validateClientVersion(request.getProtocol_version());
+ authorize(request.getRequestorUserName(),
+ getRequestorGroups(conf, request.getRequestorUserName()));
+ store.dropRole(request.getComponent(), request.getRoleName(),
+ request.getRequestorUserName());
+ return new Response<Void>(Status.OK());
+ }
+ });
+
+ TDropSentryRoleResponse tResponse = new TDropSentryRoleResponse(respose.status);
+ if (Status.OK.getCode() == respose.status.getValue()) {
+ handerInvoker.drop_sentry_role(request, tResponse);
+ }
+
+ try {
+ AUDIT_LOGGER.info(JsonLogEntityFactory.getInstance()
+ .createJsonLogEntity(request, tResponse, conf).toJsonFormatLog());
+ } catch (Exception e) {
+ // if any exception, log the exception.
+ String msg = "Error in creating audit log for drop role: " + e.getMessage();
+ LOGGER.error(msg, e);
+ }
+ return tResponse;
+ }
+
+ @Override
+ public TAlterSentryRoleGrantPrivilegeResponse alter_sentry_role_grant_privilege(
+ final TAlterSentryRoleGrantPrivilegeRequest request) throws TException {
+ Response<Void> respose = requestHandle(new RequestHandler<Void>() {
+ @Override
+ public Response<Void> handle() throws Exception {
+ validateClientVersion(request.getProtocol_version());
+ store.alterRoleGrantPrivilege(request.getComponent(),
+ request.getRoleName(),
+ toPrivilegeObject(request.getPrivilege()),
+ request.getRequestorUserName());
+ return new Response<Void>(Status.OK());
+ }
+ });
+
+ TAlterSentryRoleGrantPrivilegeResponse tResponse = new TAlterSentryRoleGrantPrivilegeResponse(respose.status);
+ if (Status.OK.getCode() == respose.status.getValue()) {
+ handerInvoker.alter_sentry_role_grant_privilege(request, tResponse);
+ }
+
+ try {
+ AUDIT_LOGGER.info(JsonLogEntityFactory.getInstance()
+ .createJsonLogEntity(request, tResponse, conf).toJsonFormatLog());
+ } catch (Exception e) {
+ // if any exception, log the exception.
+ String msg = "Error in creating audit log for grant privilege to role: " + e.getMessage();
+ LOGGER.error(msg, e);
+ }
+ return tResponse;
+ }
+
+ @Override
+ public TAlterSentryRoleRevokePrivilegeResponse alter_sentry_role_revoke_privilege(
+ final TAlterSentryRoleRevokePrivilegeRequest request) throws TException {
+ Response<Void> respose = requestHandle(new RequestHandler<Void>() {
+ @Override
+ public Response<Void> handle() throws Exception {
+ validateClientVersion(request.getProtocol_version());
+ store.alterRoleRevokePrivilege(request.getComponent(),
+ request.getRoleName(),
+ toPrivilegeObject(request.getPrivilege()),
+ request.getRequestorUserName());
+ return new Response<Void>(Status.OK());
+ }
+ });
+
+ TAlterSentryRoleRevokePrivilegeResponse tResponse =
+ new TAlterSentryRoleRevokePrivilegeResponse(respose.status);
+ if (Status.OK.getCode() == respose.status.getValue()) {
+ handerInvoker.alter_sentry_role_revoke_privilege(request, tResponse);
+ }
+
+ try {
+ AUDIT_LOGGER.info(JsonLogEntityFactory.getInstance()
+ .createJsonLogEntity(request, tResponse, conf).toJsonFormatLog());
+ } catch (Exception e) {
+ // if any exception, log the exception.
+ String msg = "Error in creating audit log for revoke privilege from role: " + e.getMessage();
+ LOGGER.error(msg, e);
+ }
+ return tResponse;
+ }
+
+ @Override
+ public TAlterSentryRoleAddGroupsResponse alter_sentry_role_add_groups(
+ final TAlterSentryRoleAddGroupsRequest request) throws TException {
+ Response<Void> respose = requestHandle(new RequestHandler<Void>() {
+ @Override
+ public Response<Void> handle() throws Exception {
+ validateClientVersion(request.getProtocol_version());
+ authorize(request.getRequestorUserName(),
+ getRequestorGroups(conf, request.getRequestorUserName()));
+ store.alterRoleAddGroups(request.getComponent(),
+ request.getRoleName(),
+ request.getGroups(),
+ request.getRequestorUserName());
+ return new Response<Void>(Status.OK());
+ }
+ });
+
+ TAlterSentryRoleAddGroupsResponse tResponse =
+ new TAlterSentryRoleAddGroupsResponse(respose.status);
+ if (Status.OK.getCode() == respose.status.getValue()) {
+ handerInvoker.alter_sentry_role_add_groups(request, tResponse);
+ }
+
+ try {
+ AUDIT_LOGGER.info(JsonLogEntityFactory.getInstance()
+ .createJsonLogEntity(request, tResponse, conf).toJsonFormatLog());
+ } catch (Exception e) {
+ // if any exception, log the exception.
+ String msg = "Error in creating audit log for add role to group: " + e.getMessage();
+ LOGGER.error(msg, e);
+ }
+ return tResponse;
+ }
+
+ @Override
+ public TAlterSentryRoleDeleteGroupsResponse alter_sentry_role_delete_groups(
+ final TAlterSentryRoleDeleteGroupsRequest request) throws TException {
+ Response<Void> respose = requestHandle(new RequestHandler<Void>() {
+ @Override
+ public Response<Void> handle() throws Exception {
+ validateClientVersion(request.getProtocol_version());
+ authorize(request.getRequestorUserName(),
+ getRequestorGroups(conf, request.getRequestorUserName()));
+ store.alterRoleDeleteGroups(request.getComponent(),
+ request.getRoleName(),
+ request.getGroups(),
+ request.getRequestorUserName());
+ return new Response<Void>(Status.OK());
+ }
+ });
+
+ TAlterSentryRoleDeleteGroupsResponse tResponse =
+ new TAlterSentryRoleDeleteGroupsResponse(respose.status);
+ if (Status.OK.getCode() == respose.status.getValue()) {
+ handerInvoker.alter_sentry_role_delete_groups(request, tResponse);
+ }
+
+ try {
+ AUDIT_LOGGER.info(JsonLogEntityFactory.getInstance()
+ .createJsonLogEntity(request, tResponse, conf).toJsonFormatLog());
+ } catch (Exception e) {
+ // if any exception, log the exception.
+ String msg = "Error in creating audit log for delete role from group: " +
+ e.getMessage();
+ LOGGER.error(msg, e);
+ }
+ return tResponse;
+ }
+
+ @Override
+ public TListSentryRolesResponse list_sentry_roles_by_group(
+ final TListSentryRolesRequest request) throws TException {
+ Response<Set<TSentryRole>> respose = requestHandle(new RequestHandler<Set<TSentryRole>>() {
+ @Override
+ public Response<Set<TSentryRole>> handle() throws Exception {
+ validateClientVersion(request.getProtocol_version());
+ Set<String> groups = getRequestorGroups(conf, request.getRequestorUserName());
+ if (!AccessConstants.ALL.equalsIgnoreCase(request.getGroupName())) {
+ boolean admin = inAdminGroups(groups);
+ //Only admin users can list all roles in the system ( groupname = null)
+ //Non admin users are only allowed to list only groups which they belong to
+ if(!admin && (request.getGroupName() == null || !groups.contains(request.getGroupName()))) {
+ throw new SentryAccessDeniedException(ACCESS_DENIAL_MESSAGE + request.getRequestorUserName());
+ }
+ groups.clear();
+ groups.add(request.getGroupName());
+ }
+
+ Set<String> roleNames = store.getRolesByGroups(request.getComponent(), groups);
+ Set<TSentryRole> tSentryRoles = Sets.newHashSet();
+ for (String roleName : roleNames) {
+ Set<String> groupsForRoleName = store.getGroupsByRoles(request.getComponent(), Sets.newHashSet(roleName));
+ tSentryRoles.add(new TSentryRole(roleName, groupsForRoleName));
+ }
+ return new Response<Set<TSentryRole>>(Status.OK(), tSentryRoles);
+ }
+ });
+ TListSentryRolesResponse tResponse = new TListSentryRolesResponse();
+ tResponse.setStatus(respose.status);
+ tResponse.setRoles(respose.content);
+ return tResponse;
+ }
+
+ @Override
+ public TListSentryPrivilegesResponse list_sentry_privileges_by_role(
+ final TListSentryPrivilegesRequest request) throws TException {
+ Response<Set<TSentryPrivilege>> respose = requestHandle(new RequestHandler<Set<TSentryPrivilege>>() {
+ @Override
+ public Response<Set<TSentryPrivilege>> handle() throws Exception {
+ validateClientVersion(request.getProtocol_version());
+ Set<String> groups = getRequestorGroups(conf, request.getRequestorUserName());
+ if (!inAdminGroups(groups)) {
+ Set<String> roleNamesForGroups = toTrimmedLower(store.getRolesByGroups(request.getComponent(), groups));
+ if (!roleNamesForGroups.contains(toTrimmedLower(request.getRoleName()))) {
+ throw new SentryAccessDeniedException(ACCESS_DENIAL_MESSAGE + request.getRequestorUserName());
+ }
+ }
+ Set<PrivilegeObject> privileges = store.getPrivilegesByProvider(request.getComponent(),
+ request.getServiceName(),
+ Sets.newHashSet(request.getRoleName()),
+ null, toAuthorizables(request.getAuthorizables()));
+ Set<TSentryPrivilege> tSentryPrivileges = Sets.newHashSet();
+ for (PrivilegeObject privilege : privileges) {
+ tSentryPrivileges.add(fromPrivilegeObject(privilege));
+ }
+ return new Response<Set<TSentryPrivilege>>(Status.OK(), tSentryPrivileges);
+ }
+ });
+ TListSentryPrivilegesResponse tResponse = new TListSentryPrivilegesResponse();
+ tResponse.setStatus(respose.status);
+ tResponse.setPrivileges(respose.content);
+ return tResponse;
+ }
+
+ @Override
+ public TListSentryPrivilegesForProviderResponse list_sentry_privileges_for_provider(
+ final TListSentryPrivilegesForProviderRequest request) throws TException {
+ Response<Set<String>> respose = requestHandle(new RequestHandler<Set<String>>() {
+ @Override
+ public Response<Set<String>> handle() throws Exception {
+ validateClientVersion(request.getProtocol_version());
+ Set<String> activeRoleNames = toTrimmedLower(request.getRoleSet().getRoles());
+ Set<String> roleNamesForGroups = store.getRolesByGroups(request.getComponent(), request.getGroups());
+ Set<String> rolesToQuery = request.getRoleSet().isAll() ? roleNamesForGroups : Sets.intersection(activeRoleNames, roleNamesForGroups);
+ Set<PrivilegeObject> privileges = store.getPrivilegesByProvider(request.getComponent(),
+ request.getServiceName(),
+ rolesToQuery, null,
+ toAuthorizables(request.getAuthorizables()));
+ return new Response<Set<String>>(Status.OK(), buildPermissions(privileges));
+ }
+ });
+ TListSentryPrivilegesForProviderResponse tResponse = new TListSentryPrivilegesForProviderResponse();
+ tResponse.setStatus(respose.status);
+ tResponse.setPrivileges(respose.content);
+ return tResponse;
+ }
+
+ @Override
+ public TListSentryPrivilegesByAuthResponse list_sentry_privileges_by_authorizable(TListSentryPrivilegesByAuthRequest request) throws TException {
+
+ TListSentryPrivilegesByAuthResponse response = new TListSentryPrivilegesByAuthResponse();
+ Map<String, TSentryPrivilegeMap> authRoleMap = Maps.newHashMap();
+
+ // Group names are case sensitive.
+ Set<String> requestedGroups = request.getGroups();
+ String subject = request.getRequestorUserName();
+ TSentryActiveRoleSet activeRoleSet = request.getRoleSet();
+ Set<String> validActiveRoles = Sets.newHashSet();
+
+ try {
+ validateClientVersion(request.getProtocol_version());
+ Set<String> memberGroups = getRequestorGroups(conf, subject);
+
+ // Disallow non-admin users to lookup groups that
+ // they are not part of.
+ if(!inAdminGroups(memberGroups)) {
+
+ if (requestedGroups != null && !requestedGroups.isEmpty()) {
+ for (String requestedGroup : requestedGroups) {
+
+ // If user doesn't belong to one of the requested groups,
+ // then raise security exception.
+ if (!memberGroups.contains(requestedGroup)) {
+ throw new SentryAccessDeniedException(ACCESS_DENIAL_MESSAGE + subject);
+ }
+ }
+ } else {
+ // Non-admin's search is limited to its own groups.
+ requestedGroups = memberGroups;
+ }
+
+ Set<String> grantedRoles = toTrimmedLower(store.getRolesByGroups(request.getComponent(), requestedGroups));
+
+ // If activeRoleSet is not null, disallow non-admin to lookup roles that they are not part of.
+ if (activeRoleSet != null && !activeRoleSet.isAll()) {
+
+ Set<String> activeRoleNames = toTrimmedLower(activeRoleSet.getRoles());
+ for (String activeRole : activeRoleNames) {
+ if (!grantedRoles.contains(activeRole)) {
+ throw new SentryAccessDeniedException(ACCESS_DENIAL_MESSAGE
+ + subject);
+ }
+ }
+
+ // For non-admin, valid active roles are intersection of active roles and granted roles.
+ validActiveRoles.addAll(activeRoleSet.isAll() ? grantedRoles : Sets.intersection(activeRoleNames, grantedRoles));
+ } else {
+ // For non-admin, if activeRoleSet is null, valid active roles would be the granted roles.
+ validActiveRoles.addAll(grantedRoles);
+ }
+ } else {
+ // For admin, if requestedGroups are empty, requested roles will be all roles.
+ Set<String> requestedRoles = toTrimmedLower(store.getAllRoleNames());
+ if (requestedGroups != null && !requestedGroups.isEmpty()) {
+ requestedRoles = toTrimmedLower(store.getRolesByGroups(request.getComponent(), requestedGroups));
+ }
+
+ // If activeRoleSet (which is optional) is not null, valid active role will be intersection
+ // of active roles and requested roles. Otherwise, valid active roles are the requested roles.
+ if (activeRoleSet != null && !activeRoleSet.isAll()) {
+ validActiveRoles.addAll(Sets.intersection(toTrimmedLower(activeRoleSet.getRoles()), requestedRoles));
+ } else {
+ validActiveRoles.addAll(requestedRoles);
+ }
+ }
+
+ // If user is not part of any group.. return empty response
+ if (request.getAuthorizablesSet() != null) {
+ for (String authorizablesStr : request.getAuthorizablesSet()) {
+
+ List<? extends Authorizable> authorizables = toAuthorizables(authorizablesStr);
+ Set<MSentryGMPrivilege> sentryPrivileges = store.getPrivilegesByAuthorizable(request.getComponent(), request.getServiceName(), validActiveRoles, authorizables);
+ authRoleMap.put(fromAuthorizableToStr(authorizables), toTSentryPrivilegeMap(sentryPrivileges));
+ }
+ }
+
+ response.setPrivilegesMapByAuth(authRoleMap);
+ response.setStatus(Status.OK());
+ } catch (SentryAccessDeniedException e) {
+ LOGGER.error(e.getMessage(), e);
+ response.setStatus(Status.AccessDenied(e.getMessage(), e));
+ } catch (SentryThriftAPIMismatchException e) {
+ LOGGER.error(e.getMessage(), e);
+ response.setStatus(Status.THRIFT_VERSION_MISMATCH(e.getMessage(), e));
+ } catch (Exception e) {
+ String msg = "Unknown error for request: " + request + ", message: "
+ + e.getMessage();
+ LOGGER.error(msg, e);
+ response.setStatus(Status.RuntimeError(msg, e));
+ }
+
+ return response;
+ }
+
+ @Override
+ public TDropPrivilegesResponse drop_sentry_privilege(
+ final TDropPrivilegesRequest request) throws TException {
+ Response<Void> respose = requestHandle(new RequestHandler<Void>() {
+ @Override
+ public Response<Void> handle() throws Exception {
+ validateClientVersion(request.getProtocol_version());
+ authorize(request.getRequestorUserName(),
+ getRequestorGroups(conf, request.getRequestorUserName()));
+ store.dropPrivilege(request.getComponent(),
+ toPrivilegeObject(request.getPrivilege()),
+ request.getRequestorUserName());
+ return new Response<Void>(Status.OK());
+ }
+ });
+
+ TDropPrivilegesResponse tResponse = new TDropPrivilegesResponse(respose.status);
+ if (Status.OK.getCode() == respose.status.getValue()) {
+ handerInvoker.drop_sentry_privilege(request, tResponse);
+ }
+ return tResponse;
+ }
+
+ @Override
+ public TRenamePrivilegesResponse rename_sentry_privilege(
+ final TRenamePrivilegesRequest request) throws TException {
+ Response<Void> respose = requestHandle(new RequestHandler<Void>() {
+ @Override
+ public Response<Void> handle() throws Exception {
+ validateClientVersion(request.getProtocol_version());
+ authorize(request.getRequestorUserName(),
+ getRequestorGroups(conf, request.getRequestorUserName()));
+ store.renamePrivilege(request.getComponent(), request.getServiceName(),
+ toAuthorizables(request.getOldAuthorizables()),
+ toAuthorizables(request.getNewAuthorizables()),
+ request.getRequestorUserName());
+ return new Response<Void>(Status.OK());
+ }
+ });
+
+ TRenamePrivilegesResponse tResponse = new TRenamePrivilegesResponse(respose.status);
+ if (Status.OK.getCode() == respose.status.getValue()) {
+ handerInvoker.rename_sentry_privilege(request, tResponse);
+ }
+ return tResponse;
+ }
+
+ private static class Response<T> {
+ private TSentryResponseStatus status;
+ private T content;
+
+ Response() {
+ }
+
+ Response(TSentryResponseStatus status) {
+ this(status, null);
+ }
+
+ Response(TSentryResponseStatus status, T content) {
+ this.status = status;
+ this.content = content;
+ }
+ }
+ private interface RequestHandler <T>{
+ Response<T> handle() throws Exception ;
+ }
+
+ private static void validateClientVersion(int protocolVersion) throws SentryThriftAPIMismatchException {
+ if (ThriftConstants.TSENTRY_SERVICE_VERSION_CURRENT != protocolVersion) {
+ String msg = "Sentry thrift API protocol version mismatch: Client thrift version " +
+ "is: " + protocolVersion + " , server thrift version " +
+ "is " + ThriftConstants.TSENTRY_SERVICE_VERSION_CURRENT;
+ throw new SentryThriftAPIMismatchException(msg);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/sentry/blob/af8ea0ac/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/api/generic/thrift/SentryGenericPolicyProcessorFactory.java
----------------------------------------------------------------------
diff --git a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/api/generic/thrift/SentryGenericPolicyProcessorFactory.java b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/api/generic/thrift/SentryGenericPolicyProcessorFactory.java
new file mode 100644
index 0000000..311b020
--- /dev/null
+++ b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/api/generic/thrift/SentryGenericPolicyProcessorFactory.java
@@ -0,0 +1,44 @@
+/**
+ * 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.sentry.api.generic.thrift;
+
+import org.apache.hadoop.conf.Configuration;
+import org.apache.sentry.api.common.ApiConstants.SentryPolicyServiceConstants;
+import org.apache.sentry.provider.db.service.persistent.SentryStore;
+import org.apache.sentry.service.thrift.ProcessorFactory;
+import org.apache.thrift.TMultiplexedProcessor;
+import org.apache.thrift.TProcessor;
+
+public class SentryGenericPolicyProcessorFactory extends ProcessorFactory {
+
+ public SentryGenericPolicyProcessorFactory(Configuration conf) {
+ super(conf);
+ }
+
+ @Override
+ public boolean register(TMultiplexedProcessor multiplexedProcessor,
+ SentryStore _) throws Exception {
+ SentryGenericPolicyProcessor processHandler = new SentryGenericPolicyProcessor(conf);
+ TProcessor processor = new SentryGenericPolicyProcessorWrapper<SentryGenericPolicyService.Iface>(
+ processHandler);
+ multiplexedProcessor.registerProcessor(
+ SentryPolicyServiceConstants.SENTRY_GENERIC_SERVICE_NAME, processor);
+ return true;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/sentry/blob/af8ea0ac/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/api/service/thrift/ConfServlet.java
----------------------------------------------------------------------
diff --git a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/api/service/thrift/ConfServlet.java b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/api/service/thrift/ConfServlet.java
new file mode 100644
index 0000000..8625487
--- /dev/null
+++ b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/api/service/thrift/ConfServlet.java
@@ -0,0 +1,71 @@
+package org.apache.sentry.api.service.thrift;
+
+/**
+ * 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.
+ */
+
+import java.io.IOException;
+import java.io.Writer;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.hadoop.conf.Configuration;
+
+import static org.apache.commons.lang.StringEscapeUtils.escapeHtml;
+
+/**
+ * Servlet to print out all sentry configuration.
+ */
+public class ConfServlet extends HttpServlet {
+ public static final String CONF_CONTEXT_ATTRIBUTE = "sentry.conf";
+ public static final String FORMAT_JSON = "json";
+ public static final String FORMAT_XML = "xml";
+ public static final String FORMAT_PARAM = "format";
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public void doGet(HttpServletRequest request, HttpServletResponse response)
+ throws ServletException, IOException {
+ String format = request.getParameter(FORMAT_PARAM);
+ if (format == null) {
+ format = FORMAT_XML;
+ }
+
+ if (FORMAT_XML.equals(format)) {
+ response.setContentType("text/xml; charset=utf-8");
+ } else if (FORMAT_JSON.equals(format)) {
+ response.setContentType("application/json; charset=utf-8");
+ }
+
+ Configuration conf = (Configuration)getServletContext().getAttribute(
+ CONF_CONTEXT_ATTRIBUTE);
+ assert conf != null;
+
+ Writer out = response.getWriter();
+ if (FORMAT_JSON.equals(format)) {
+ Configuration.dumpConfiguration(conf, out);
+ } else if (FORMAT_XML.equals(format)) {
+ conf.writeXml(out);
+ } else {
+ response.sendError(HttpServletResponse.SC_BAD_REQUEST, "Bad format: " + escapeHtml(format));
+ }
+ out.close();
+ }
+}
http://git-wip-us.apache.org/repos/asf/sentry/blob/af8ea0ac/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/api/service/thrift/LogLevelServlet.java
----------------------------------------------------------------------
diff --git a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/api/service/thrift/LogLevelServlet.java b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/api/service/thrift/LogLevelServlet.java
new file mode 100644
index 0000000..af81d6f
--- /dev/null
+++ b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/api/service/thrift/LogLevelServlet.java
@@ -0,0 +1,122 @@
+/**
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.sentry.api.service.thrift;
+
+import org.apache.log4j.Level;
+import org.apache.log4j.LogManager;
+import org.apache.log4j.Logger;
+
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.io.PrintWriter;
+
+import static org.apache.commons.lang.StringEscapeUtils.escapeHtml;
+
+public class LogLevelServlet extends HttpServlet {
+ private static final String LF = "\n";
+ private static final String BR = "<br />";
+ private static final String B_BR = "<b>%s</b><br />";
+ private static final String FORMS_HEAD =
+ "<h1>" + "Log Level" + "</h1>"
+ + LF + BR + "<hr /><h3>Results</h3>"
+ + LF + " Submitted Log Name: " + B_BR;
+ private static final String FORMS_CONTENT_GET =
+ LF + " Effective level: " + B_BR;
+ private static final String FORMS_CONTENT_SET =
+ LF + " Submitted Level: " + B_BR
+ + LF + " Setting Level to %s" + BR
+ + LF + " Effective level: " + B_BR;
+ private static final String FORMS_END =
+ LF + BR + "<hr /><h3>Get / Set</h3>"
+ + LF + "<form>Log: <input type='text' size='50' name='log' /> "
+ + "<input type='submit' value='Get Log Level' />" + "</form>"
+ + LF + "<form>Log: <input type='text' size='50' name='log' /> "
+ + "Level: <input type='text' name='level' /> "
+ + "<input type='submit' value='Set Log Level' />" + "</form>";
+ private static final String FORMS_GET = FORMS_HEAD + FORMS_CONTENT_GET;
+ private static final String FORMS_SET = FORMS_HEAD + FORMS_CONTENT_SET;
+
+ /**
+ * Return parameter on servlet request for the given name
+ *
+ * @param request: Servlet request
+ * @param name: Name of parameter in servlet request
+ * @return Parameter in servlet request for the given name, return null if can't find parameter.
+ */
+ private String getParameter(ServletRequest request, String name) {
+ String s = request.getParameter(name);
+ if (s == null) {
+ return null;
+ }
+ s = s.trim();
+ return s.length() == 0 ? null : s;
+ }
+
+ /**
+ * Check the validity of the log level.
+ * @param level: The log level to be checked
+ * @return
+ * true: The log level is valid
+ * false: The log level is invalid
+ */
+ private boolean isLogLevelValid(String level) {
+ return level.equals(Level.toLevel(level).toString());
+ }
+
+ /**
+ * Parse the class name and log level in the http servlet request.
+ * If the request contains only class name, return the log level in the response message.
+ * If the request contains both class name and level, set the log level to the requested level
+ * and return the setting result in the response message.
+ */
+ @Override
+ public void doGet(HttpServletRequest request, HttpServletResponse response)
+ throws ServletException, IOException {
+ String logName = getParameter(request, "log");
+ String level = getParameter(request, "level");
+ response.setContentType("text/html;charset=utf-8");
+ response.setStatus(HttpServletResponse.SC_OK);
+ PrintWriter out = response.getWriter();
+
+ if (logName != null) {
+ Logger logInstance = LogManager.getLogger(logName);
+ if (level == null) {
+ out.write(String.format(FORMS_GET,
+ escapeHtml(logName),
+ logInstance.getEffectiveLevel().toString()));
+ } else if (isLogLevelValid(level)) {
+ logInstance.setLevel(Level.toLevel(level));
+ out.write(String.format(FORMS_SET,
+ escapeHtml(logName),
+ escapeHtml(level),
+ escapeHtml(level),
+ logInstance.getEffectiveLevel().toString()));
+ } else {
+ response.sendError(HttpServletResponse.SC_BAD_REQUEST, "Invalid log level: " + escapeHtml(level));
+ return;
+ }
+ }
+ out.write(FORMS_END);
+ out.close();
+ response.flushBuffer();
+ }
+}
http://git-wip-us.apache.org/repos/asf/sentry/blob/af8ea0ac/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/api/service/thrift/PubSubServlet.java
----------------------------------------------------------------------
diff --git a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/api/service/thrift/PubSubServlet.java b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/api/service/thrift/PubSubServlet.java
new file mode 100644
index 0000000..8da35f1
--- /dev/null
+++ b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/api/service/thrift/PubSubServlet.java
@@ -0,0 +1,128 @@
+/**
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.sentry.api.service.thrift;
+
+import org.apache.sentry.core.common.utils.PubSub;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.io.PrintWriter;
+
+import static org.apache.commons.lang.StringEscapeUtils.escapeHtml;
+
+/**
+ * This servlet facilitates sending {topic, message } tuples to Servlet components
+ * subscribed to specific topics.
+ * <p>
+ * It uses publish-subscribe mechanism implemented by PubSub class.
+ * The form generated by this servlet consists of the following elements:
+ * <p>
+ * a) Topic: pull-down menu of existing topics, i.e. the topics registered with
+ * PubSub by calling PubSub.subscribe() API. This prevents entering invalid topic.
+ * <p>
+ * b) Message: text field for entering a message
+ * <p>
+ * c) Submit: button to submit (topic, message) tuple
+ * <p>
+ * d) Status: text area printing status of the request or help information.
+ */
+public class PubSubServlet extends HttpServlet {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(PubSubServlet.class);
+
+ private static final String FORM_GET =
+ "<!DOCTYPE html>" +
+ "<html>" +
+ "<body>" +
+ "<form>" +
+ "<br><br><b>Topic:</b><br><br>" +
+ "<select name='topic'/>%s</select>" +
+ "<br><br><b>Message:</b><br><br>" +
+ "<input type='text' size='50' name='message'/>" +
+ "<br><br>" +
+ "<input type='submit' value='Submit'/>" +
+ "</form>" +
+ "<br><br><b>Status:</b><br><br>" +
+ "<textarea rows='4' cols='50'>%s</textarea>" +
+ "</body>" +
+ "</html>";
+
+ /**
+ * Return parameter on servlet request for the given name
+ *
+ * @param request: Servlet request
+ * @param name: Name of parameter in servlet request
+ * @return Parameter in servlet request for the given name, return null if can't find parameter.
+ */
+ private static String getParameter(ServletRequest request, String name) {
+ String s = request.getParameter(name);
+ if (s == null) {
+ return null;
+ }
+ s = s.trim();
+ return s.isEmpty() ? null : s;
+ }
+
+ /**
+ * Parse the topic and message values and submit them via PubSub.submit() API.
+ * Reject request for unknown topic, i.e. topic no one is subscribed to.
+ */
+ @Override
+ public void doGet(HttpServletRequest request, HttpServletResponse response)
+ throws ServletException, IOException {
+ String topic = getParameter(request, "topic");
+ String message = getParameter(request, "message");
+ response.setContentType("text/html;charset=utf-8");
+ response.setStatus(HttpServletResponse.SC_OK);
+ PrintWriter out = response.getWriter();
+
+ String msg = "Topic is required, Message is optional.\nValid topics: " + PubSub.getInstance().getTopics();
+ if (topic != null) {
+ LOGGER.info("Submitting topic " + topic + ", message " + message);
+ try {
+ PubSub.getInstance().publish(PubSub.Topic.fromString(topic), message);
+ msg = "Submitted topic " + topic + ", message " + message;
+ } catch (Exception e) {
+ msg = "Failed to submit topic " + topic + ", message " + message + " - " + e.getMessage();
+ LOGGER.error(msg);
+ response.sendError(HttpServletResponse.SC_BAD_REQUEST, msg);
+ return;
+ }
+ }
+
+ StringBuilder topics = new StringBuilder();
+ for (PubSub.Topic t : PubSub.getInstance().getTopics()) {
+ topics.append("<option>").append(t.getName()).append("</option>");
+ }
+
+ String output = String.format(FORM_GET, topics.toString(), escapeHtml(msg));
+ if (LOGGER.isDebugEnabled()) {
+ LOGGER.debug("HTML Page: " + output);
+ }
+ out.write(output);
+ out.close();
+ response.flushBuffer();
+ }
+}
http://git-wip-us.apache.org/repos/asf/sentry/blob/af8ea0ac/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/api/service/thrift/SentryAdminServlet.java
----------------------------------------------------------------------
diff --git a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/api/service/thrift/SentryAdminServlet.java b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/api/service/thrift/SentryAdminServlet.java
new file mode 100644
index 0000000..5dc6cd6
--- /dev/null
+++ b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/api/service/thrift/SentryAdminServlet.java
@@ -0,0 +1,132 @@
+/**
+ * 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.sentry.api.service.thrift;
+
+import com.google.gson.Gson;
+import org.apache.hadoop.conf.Configuration;
+import org.apache.sentry.provider.db.service.persistent.SentryStore;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.Writer;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Admin Servlet is only used when SENTRY_WEB_ADMIN_SERVLET_ENABLED is true.
+ */
+public class SentryAdminServlet extends HttpServlet {
+ private static final String SHOW_ALL = "/showAll";
+ // Here we use the same way as in com.codahale.metrics.servlets.AdminServlet, and just
+ // use the TEMPLATE as a static html with some links referenced to other debug pages.
+ private static final String TEMPLATE = "<!DOCTYPE HTML>\n"+
+ "<html lang=\"en\">\n"+
+ "<head>\n"+
+ " <meta charset=\"utf-8\">\n"+
+ " <title>Sentry Service Admin</title>\n"+
+ " <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n"+
+ " <meta name=\"description\" content=\"\">\n"+
+ " <link href=\"css/bootstrap.min.css\" rel=\"stylesheet\">\n"+
+ " <link href=\"css/bootstrap-theme.min.css\" rel=\"stylesheet\">\n"+
+ " <link href=\"css/sentry.css\" rel=\"stylesheet\">\n"+
+ "</head>\n"+
+ "<body>\n"+
+ "<nav class=\"navbar navbar-default navbar-fixed-top\">\n"+
+ " <div class=\"container\">\n"+
+ " <div class=\"navbar-header\">\n"+
+ " <a class=\"navbar-brand\" href=\"#\"><img src=\"sentry.png\" alt=\"Sentry Logo\"/></a>\n"+
+ " </div>\n"+
+ " <div class=\"collapse navbar-collapse\">\n"+
+ " <ul class=\"nav navbar-nav\">\n"+
+ " <li class=\"active\"><a href=\"#\">Admin</a></li>\n"+
+ " <li><a href=\"/metrics?pretty=true\">Metrics</a></li>\n"+
+ " <li><a href=\"/threads\">Threads</a></li>\n"+
+ " <li><a href=\"/conf\">Configuration</a></li>\n"+
+ " <li><a href=\"/admin/showAll\">ShowAllRoles</a></li>\n"+
+ " </ul>\n"+
+ " </div>\n"+
+ " </div>\n"+
+ "</nav>\n"+
+ "<div class=\"container\">\n"+
+ " <ul>\n"+
+ " <li><a href=\"/metrics?pretty=true\">Metrics</a></li>\n"+
+ " <li><a href=\"/threads\">Threads</a></li>\n"+
+ " <li><a href=\"/conf\">Configuration</a></li>\n"+
+ " <li><a href=\"/admin/showAll\">ShowAllRoles</a></li>\n"+
+ " </ul>\n"+
+ "</div>\n"+
+ "</body>\n"+
+ "</html>";
+
+ @Override
+ public void doGet(HttpServletRequest request, HttpServletResponse response)
+ throws ServletException, IOException {
+ String uri = request.getPathInfo();
+ if(uri != null && !uri.equals("/")) {
+ if (uri.equals(SHOW_ALL)) {
+ showAll(response);
+ } else {
+ response.sendError(404);
+ }
+ } else {
+ response.setStatus(200);
+ response.setHeader("Cache-Control", "must-revalidate,no-cache,no-store");
+ response.setHeader("Pragma", "no-cache");
+ response.setDateHeader("Expires", 0);
+ response.setContentType("text/html");
+ PrintWriter writer = response.getWriter();
+ try {
+ writer.println(TEMPLATE);
+ } finally {
+ writer.close();
+ }
+ }
+ }
+
+ /**
+ * Print out all the roles and privileges information as json format.
+ */
+ private void showAll(HttpServletResponse response)
+ throws ServletException, IOException {
+ Configuration conf = (Configuration)getServletContext().getAttribute(
+ ConfServlet.CONF_CONTEXT_ATTRIBUTE);
+ assert conf != null;
+
+ Writer out = response.getWriter();
+ try {
+ SentryStore sentrystore = new SentryStore(conf);
+ Map<String, Set<TSentryPrivilege>> roleMap = new HashMap<>();
+ Set<String> roleSet = sentrystore.getAllRoleNames();
+ for (String roleName: roleSet) {
+ roleMap.put(roleName, sentrystore.getAllTSentryPrivilegesByRoleName(roleName));
+ }
+ String json = new Gson().toJson(roleMap);
+ response.setContentType("application/json");
+ response.setCharacterEncoding("UTF-8");
+ out.write(json);
+ } catch (Exception e) {
+ response.sendError(HttpServletResponse.SC_BAD_REQUEST, e.getMessage());
+ }
+ out.close();
+ }
+}
http://git-wip-us.apache.org/repos/asf/sentry/blob/af8ea0ac/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/api/service/thrift/SentryAuthFilter.java
----------------------------------------------------------------------
diff --git a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/api/service/thrift/SentryAuthFilter.java b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/api/service/thrift/SentryAuthFilter.java
new file mode 100644
index 0000000..23121ec
--- /dev/null
+++ b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/api/service/thrift/SentryAuthFilter.java
@@ -0,0 +1,89 @@
+/**
+ * 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.sentry.api.service.thrift;
+
+import java.io.IOException;
+import java.util.Enumeration;
+import java.util.Properties;
+import java.util.Set;
+
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.hadoop.security.authentication.server.AuthenticationFilter;
+import org.apache.hadoop.util.StringUtils;
+import org.apache.sentry.service.common.ServiceConstants.ServerConfig;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.Sets;
+
+/**
+ * SentryAuthFilter is a subclass of AuthenticationFilter,
+ * add authorization: Only allowed users could connect the web server.
+ */
+public class SentryAuthFilter extends AuthenticationFilter {
+
+ private static final Logger LOG = LoggerFactory.getLogger(SentryAuthFilter.class);
+
+ public static final String ALLOW_WEB_CONNECT_USERS = ServerConfig.SENTRY_WEB_SECURITY_ALLOW_CONNECT_USERS;
+
+ private Set<String> allowUsers;
+
+ @Override
+ protected void doFilter(FilterChain filterChain, HttpServletRequest request,
+ HttpServletResponse response) throws IOException, ServletException {
+ String userName = request.getRemoteUser();
+ LOG.debug("Authenticating user: " + userName + " from request.");
+ if (!allowUsers.contains(userName)) {
+ response.sendError(HttpServletResponse.SC_FORBIDDEN,
+ "Unauthorized user status code: " + HttpServletResponse.SC_FORBIDDEN);
+ throw new ServletException(userName + " is unauthorized. status code: " + HttpServletResponse.SC_FORBIDDEN);
+ }
+ super.doFilter(filterChain, request, response);
+ }
+
+ /**
+ * Override <code>getConfiguration<code> to get <code>ALLOW_WEB_CONNECT_USERS<code>.
+ */
+ @Override
+ protected Properties getConfiguration(String configPrefix, FilterConfig filterConfig) throws ServletException {
+ Properties props = new Properties();
+ Enumeration<?> names = filterConfig.getInitParameterNames();
+ while (names.hasMoreElements()) {
+ String name = (String) names.nextElement();
+ if (name.startsWith(configPrefix)) {
+ String value = filterConfig.getInitParameter(name);
+ if (ALLOW_WEB_CONNECT_USERS.equals(name)) {
+ allowUsers = parseConnectUsersFromConf(value);
+ } else {
+ props.put(name.substring(configPrefix.length()), value);
+ }
+ }
+ }
+ return props;
+ }
+
+ private static Set<String> parseConnectUsersFromConf(String value) {
+ //Removed the logic to convert the allowed users to lower case, as user names need to be case sensitive
+ return Sets.newHashSet(StringUtils.getStrings(value));
+ }
+}
http://git-wip-us.apache.org/repos/asf/sentry/blob/af8ea0ac/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/api/service/thrift/SentryHealthCheckServletContextListener.java
----------------------------------------------------------------------
diff --git a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/api/service/thrift/SentryHealthCheckServletContextListener.java b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/api/service/thrift/SentryHealthCheckServletContextListener.java
new file mode 100644
index 0000000..eb11c19
--- /dev/null
+++ b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/api/service/thrift/SentryHealthCheckServletContextListener.java
@@ -0,0 +1,35 @@
+/**
+ * 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.sentry.api.service.thrift;
+
+import com.codahale.metrics.health.HealthCheckRegistry;
+import com.codahale.metrics.servlets.HealthCheckServlet;
+
+/**
+ * Use this class's registry to register health checks: Can be some tests which make sure Sentry service is healthy
+ */
+public class SentryHealthCheckServletContextListener extends HealthCheckServlet.ContextListener {
+
+ //This is just a place holder for health check registry, with out this AdminServlet throws out an error
+ public static final HealthCheckRegistry HEALTH_CHECK_REGISTRY = new HealthCheckRegistry();
+
+ @Override
+ protected HealthCheckRegistry getHealthCheckRegistry() {
+ return HEALTH_CHECK_REGISTRY;
+ }
+}
\ No newline at end of file