From commits-return-12515-archive-asf-public=cust-asf.ponee.io@sentry.apache.org Thu May 10 02:14:19 2018 Return-Path: X-Original-To: archive-asf-public@cust-asf.ponee.io Delivered-To: archive-asf-public@cust-asf.ponee.io Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by mx-eu-01.ponee.io (Postfix) with SMTP id 92CE91807D5 for ; Thu, 10 May 2018 02:14:13 +0200 (CEST) Received: (qmail 24890 invoked by uid 500); 10 May 2018 00:14:12 -0000 Mailing-List: contact commits-help@sentry.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@sentry.apache.org Delivered-To: mailing list commits@sentry.apache.org Received: (qmail 23767 invoked by uid 99); 10 May 2018 00:14:12 -0000 Received: from git1-us-west.apache.org (HELO git1-us-west.apache.org) (140.211.11.23) by apache.org (qpsmtpd/0.29) with ESMTP; Thu, 10 May 2018 00:14:11 +0000 Received: by git1-us-west.apache.org (ASF Mail Server at git1-us-west.apache.org, from userid 33) id DA8A2F6CC1; Thu, 10 May 2018 00:14:10 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: spena@apache.org To: commits@sentry.apache.org Date: Thu, 10 May 2018 00:14:35 -0000 Message-Id: In-Reply-To: <6ba30d4b15f6490fa8a071acb6d4aa80@git.apache.org> References: <6ba30d4b15f6490fa8a071acb6d4aa80@git.apache.org> X-Mailer: ASF-Git Admin Mailer Subject: [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, java.io.Serializable, Cloneable, Comparable { - 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, SchemeFactory> schemes = new HashMap, 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 byName = new HashMap(); - - 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 other. - */ - 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 list = new ArrayList(); - - 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 { - - 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 { - - @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 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 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 toTrimmedLower(Set s) { + if (s == null) { + return Collections.emptySet(); + } + Set result = new HashSet<>(s.size()); + for (String v : s) { + result.add(v.trim().toLowerCase()); + } + return result; + } + + private Set toTrimmed(Set s) { + if (s == null) { + return Collections.emptySet(); + } + Set 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 getRequestorGroups(Configuration conf, String userName) throws SentryUserException { + return SentryPolicyStoreProcessor.getGroupsFromUserName(conf, userName); + } + + private boolean inAdminGroups(Set requestorGroups) { + return !Sets.intersection(adminGroups, requestorGroups).isEmpty(); + } + + static List createHandlers(Configuration conf) throws SentrySiteConfigurationException { + + List handlers = Lists.newArrayList(); + Iterable 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 createInstance(String className, Configuration conf, Class 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 meth = (Constructor)clazz.getDeclaredConstructor(Configuration.class); + meth.setAccessible(true); + result = meth.newInstance(new Object[]{conf}); + } catch (Exception e) { + throw new RuntimeException(e); + } + return result; + } + + private Response requestHandle(RequestHandler handler) { + Response response = new Response(); + 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 fromAuthorizable(List authorizables) { + List tAuthorizables = Lists.newArrayList(); + for (Authorizable authorizable : authorizables) { + tAuthorizables.add(new TAuthorizable(authorizable.getTypeName(), authorizable.getName())); + } + return tAuthorizables; + } + + private String fromAuthorizableToStr(List authorizables) { + if (authorizables != null && !authorizables.isEmpty()) { + List 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 toAuthorizables(List tAuthorizables) { + List 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 toAuthorizables(String privilegeStr) { + List 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 mPrivileges) { + + // Mapping of >. + Map> 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 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 buildPermissions(Set privileges) { + Set permissions = Sets.newHashSet(); + for (PrivilegeObject privilege : privileges) { + List 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 respose = requestHandle(new RequestHandler() { + @Override + public Response 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(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 respose = requestHandle(new RequestHandler() { + @Override + public Response 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(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 respose = requestHandle(new RequestHandler() { + @Override + public Response handle() throws Exception { + validateClientVersion(request.getProtocol_version()); + store.alterRoleGrantPrivilege(request.getComponent(), + request.getRoleName(), + toPrivilegeObject(request.getPrivilege()), + request.getRequestorUserName()); + return new Response(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 respose = requestHandle(new RequestHandler() { + @Override + public Response handle() throws Exception { + validateClientVersion(request.getProtocol_version()); + store.alterRoleRevokePrivilege(request.getComponent(), + request.getRoleName(), + toPrivilegeObject(request.getPrivilege()), + request.getRequestorUserName()); + return new Response(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 respose = requestHandle(new RequestHandler() { + @Override + public Response 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(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 respose = requestHandle(new RequestHandler() { + @Override + public Response 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(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> respose = requestHandle(new RequestHandler>() { + @Override + public Response> handle() throws Exception { + validateClientVersion(request.getProtocol_version()); + Set 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 roleNames = store.getRolesByGroups(request.getComponent(), groups); + Set tSentryRoles = Sets.newHashSet(); + for (String roleName : roleNames) { + Set groupsForRoleName = store.getGroupsByRoles(request.getComponent(), Sets.newHashSet(roleName)); + tSentryRoles.add(new TSentryRole(roleName, groupsForRoleName)); + } + return new Response>(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> respose = requestHandle(new RequestHandler>() { + @Override + public Response> handle() throws Exception { + validateClientVersion(request.getProtocol_version()); + Set groups = getRequestorGroups(conf, request.getRequestorUserName()); + if (!inAdminGroups(groups)) { + Set roleNamesForGroups = toTrimmedLower(store.getRolesByGroups(request.getComponent(), groups)); + if (!roleNamesForGroups.contains(toTrimmedLower(request.getRoleName()))) { + throw new SentryAccessDeniedException(ACCESS_DENIAL_MESSAGE + request.getRequestorUserName()); + } + } + Set privileges = store.getPrivilegesByProvider(request.getComponent(), + request.getServiceName(), + Sets.newHashSet(request.getRoleName()), + null, toAuthorizables(request.getAuthorizables())); + Set tSentryPrivileges = Sets.newHashSet(); + for (PrivilegeObject privilege : privileges) { + tSentryPrivileges.add(fromPrivilegeObject(privilege)); + } + return new Response>(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> respose = requestHandle(new RequestHandler>() { + @Override + public Response> handle() throws Exception { + validateClientVersion(request.getProtocol_version()); + Set activeRoleNames = toTrimmedLower(request.getRoleSet().getRoles()); + Set roleNamesForGroups = store.getRolesByGroups(request.getComponent(), request.getGroups()); + Set rolesToQuery = request.getRoleSet().isAll() ? roleNamesForGroups : Sets.intersection(activeRoleNames, roleNamesForGroups); + Set privileges = store.getPrivilegesByProvider(request.getComponent(), + request.getServiceName(), + rolesToQuery, null, + toAuthorizables(request.getAuthorizables())); + return new Response>(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 authRoleMap = Maps.newHashMap(); + + // Group names are case sensitive. + Set requestedGroups = request.getGroups(); + String subject = request.getRequestorUserName(); + TSentryActiveRoleSet activeRoleSet = request.getRoleSet(); + Set validActiveRoles = Sets.newHashSet(); + + try { + validateClientVersion(request.getProtocol_version()); + Set 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 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 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 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 authorizables = toAuthorizables(authorizablesStr); + Set 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 respose = requestHandle(new RequestHandler() { + @Override + public Response 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(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 respose = requestHandle(new RequestHandler() { + @Override + public Response 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(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 { + 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 { + Response 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( + 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 + *

+ * 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 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 = "
"; + private static final String B_BR = "%s
"; + private static final String FORMS_HEAD = + "

" + "Log Level" + "

" + + LF + BR + "

Results

" + + 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 + "

Get / Set

" + + LF + "
Log: " + + "" + "
" + + LF + "
Log: " + + "Level: " + + "" + "
"; + 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 + *

+ * 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 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. + *

+ * It uses publish-subscribe mechanism implemented by PubSub class. + * The form generated by this servlet consists of the following elements: + *

+ * 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. + *

+ * b) Message: text field for entering a message + *

+ * c) Submit: button to submit (topic, message) tuple + *

+ * 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 = + "" + + "" + + "" + + "

" + + "

Topic:

" + + "" + + "

Message:

" + + "" + + "

" + + "" + + "
" + + "

Status:

" + + "" + + "" + + ""; + + /** + * 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(""); + } + + 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 = "\n"+ + "\n"+ + "\n"+ + " \n"+ + " Sentry Service Admin\n"+ + " \n"+ + " \n"+ + " \n"+ + " \n"+ + " \n"+ + "\n"+ + "\n"+ + "\n"+ + "
\n"+ + " \n"+ + "
\n"+ + "\n"+ + ""; + + @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> roleMap = new HashMap<>(); + Set 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 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 getConfiguration to get ALLOW_WEB_CONNECT_USERS. + */ + @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 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