http://git-wip-us.apache.org/repos/asf/sentry/blob/9351d19d/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/log/appender/RollingFileWithoutDeleteAppender.java ---------------------------------------------------------------------- diff --git a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/log/appender/RollingFileWithoutDeleteAppender.java b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/log/appender/RollingFileWithoutDeleteAppender.java new file mode 100644 index 0000000..fd133f3 --- /dev/null +++ b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/log/appender/RollingFileWithoutDeleteAppender.java @@ -0,0 +1,175 @@ +/** + * 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.provider.db.log.appender; + +import java.io.File; +import java.io.IOException; +import java.io.InterruptedIOException; +import java.io.Writer; + +import org.apache.log4j.FileAppender; +import org.apache.log4j.Layout; +import org.apache.log4j.helpers.CountingQuietWriter; +import org.apache.log4j.helpers.LogLog; +import org.apache.log4j.helpers.OptionConverter; +import org.apache.log4j.spi.LoggingEvent; + +public class RollingFileWithoutDeleteAppender extends FileAppender { + /** + * The default maximum file size is 10MB. + */ + protected long maxFileSize = 10 * 1024 * 1024; + + private long nextRollover = 0; + + /** + * The default constructor simply calls its {@link FileAppender#FileAppender + * parents constructor}. + */ + public RollingFileWithoutDeleteAppender() { + super(); + } + + /** + * Instantiate a RollingFileAppender and open the file designated by + * <code>filename</code>. The opened filename will become the ouput + * destination for this appender. + * <p> + * If the <code>append</code> parameter is true, the file will be appended to. + * Otherwise, the file desginated by <code>filename</code> will be truncated + * before being opened. + */ + public RollingFileWithoutDeleteAppender(Layout layout, String filename, + boolean append) throws IOException { + super(layout, getLogFileName(filename), append); + } + + /** + * Instantiate a FileAppender and open the file designated by + * <code>filename</code>. The opened filename will become the output + * destination for this appender. + * <p> + * The file will be appended to. + */ + public RollingFileWithoutDeleteAppender(Layout layout, String filename) + throws IOException { + super(layout, getLogFileName(filename)); + } + + /** + * Get the maximum size that the output file is allowed to reach before being + * rolled over to backup files. + */ + public long getMaximumFileSize() { + return maxFileSize; + } + + /** + * Implements the usual roll over behaviour. + * <p> + * <code>File</code> is renamed <code>File.yyyyMMddHHmmss</code> and closed. A + * new <code>File</code> is created to receive further log output. + */ + // synchronization not necessary since doAppend is alreasy synched + public void rollOver() { + if (qw != null) { + long size = ((CountingQuietWriter) qw).getCount(); + LogLog.debug("rolling over count=" + size); + // if operation fails, do not roll again until + // maxFileSize more bytes are written + nextRollover = size + maxFileSize; + } + + this.closeFile(); // keep windows happy. + + String newFileName = getLogFileName(fileName); + try { + // This will also close the file. This is OK since multiple + // close operations are safe. + this.setFile(newFileName, false, bufferedIO, bufferSize); + nextRollover = 0; + } catch (IOException e) { + if (e instanceof InterruptedIOException) { + Thread.currentThread().interrupt(); + } + LogLog.error("setFile(" + newFileName + ", false) call failed: " + e.getMessage(), e); + } + } + + public synchronized void setFile(String fileName, boolean append, + boolean bufferedIO, int bufferSize) throws IOException { + super.setFile(fileName, append, this.bufferedIO, this.bufferSize); + if (append) { + File f = new File(fileName); + ((CountingQuietWriter) qw).setCount(f.length()); + } + } + + /** + * Set the maximum size that the output file is allowed to reach before being + * rolled over to backup files. + * <p> + * This method is equivalent to {@link #setMaxFileSize} except that it is + * required for differentiating the setter taking a <code>long</code> argument + * from the setter taking a <code>String</code> argument by the JavaBeans + * {@link java.beans.Introspector Introspector}. + * + * @see #setMaxFileSize(String) + */ + public void setMaximumFileSize(long maxFileSize) { + this.maxFileSize = maxFileSize; + } + + /** + * Set the maximum size that the output file is allowed to reach before being + * rolled over to backup files. + * <p> + * In configuration files, the <b>MaxFileSize</b> option takes an long integer + * in the range 0 - 2^63. You can specify the value with the suffixes "KB", + * "MB" or "GB" so that the integer is interpreted being expressed + * respectively in kilobytes, megabytes or gigabytes. For example, the value + * "10KB" will be interpreted as 10240. + */ + public void setMaxFileSize(String value) { + maxFileSize = OptionConverter.toFileSize(value, maxFileSize + 1); + } + + protected void setQWForFiles(Writer writer) { + this.qw = new CountingQuietWriter(writer, errorHandler); + } + + /** + * This method differentiates RollingFileAppender from its super class. + */ + protected void subAppend(LoggingEvent event) { + super.subAppend(event); + + if (fileName != null && qw != null) { + long size = ((CountingQuietWriter) qw).getCount(); + if (size >= maxFileSize && size >= nextRollover) { + rollOver(); + } + } + } + + // Mangled file name. Append the current timestamp + private static String getLogFileName(String oldFileName) { + return oldFileName + "." + Long.toString(System.currentTimeMillis()); + } +}
http://git-wip-us.apache.org/repos/asf/sentry/blob/9351d19d/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/log/entity/AuditMetadataLogEntity.java ---------------------------------------------------------------------- diff --git a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/log/entity/AuditMetadataLogEntity.java b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/log/entity/AuditMetadataLogEntity.java new file mode 100644 index 0000000..a5fe4ec --- /dev/null +++ b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/log/entity/AuditMetadataLogEntity.java @@ -0,0 +1,155 @@ +/** + * 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.provider.db.log.entity; + +import java.io.IOException; + +import org.codehaus.jackson.JsonFactory; +import org.codehaus.jackson.JsonNode; +import org.codehaus.jackson.map.MappingJsonFactory; +import org.codehaus.jackson.map.ObjectMapper; +import org.codehaus.jackson.node.ContainerNode; + +abstract public class AuditMetadataLogEntity implements JsonLogEntity { + + static final JsonFactory factory = new MappingJsonFactory(); + private String serviceName; + private String userName; + private String impersonator; + private String ipAddress; + private String operation; + private String eventTime; + private String operationText; + private String allowed; + private String objectType; + private String component; + + void setCommonAttr(String serviceName, String userName, String impersonator, String ipAddress, + String operation, String eventTime, String operationText, String allowed, String objectType, + String component) { + this.serviceName = serviceName; + this.userName = userName; + this.impersonator = impersonator; + this.ipAddress = ipAddress; + this.operation = operation; + this.eventTime = eventTime; + this.operationText = operationText; + this.allowed = allowed; + this.objectType = objectType; + this.component = component; + } + + public String getServiceName() { + return serviceName; + } + + public void setServiceName(String serviceName) { + this.serviceName = serviceName; + } + + public String getUserName() { + return userName; + } + + public void setUserName(String userName) { + this.userName = userName; + } + + public String getImpersonator() { + return impersonator; + } + + public void setImpersonator(String impersonator) { + this.impersonator = impersonator; + } + + public String getIpAddress() { + return ipAddress; + } + + public void setIpAddress(String ipAddress) { + this.ipAddress = ipAddress; + } + + public String getOperation() { + return operation; + } + + public void setOperation(String operation) { + this.operation = operation; + } + + public String getEventTime() { + return eventTime; + } + + public void setEventTime(String eventTime) { + this.eventTime = eventTime; + } + + public String getOperationText() { + return operationText; + } + + public void setOperationText(String operationText) { + this.operationText = operationText; + } + + public String getAllowed() { + return allowed; + } + + public void setAllowed(String allowed) { + this.allowed = allowed; + } + + public String getObjectType() { + return objectType; + } + + public void setObjectType(String objectType) { + this.objectType = objectType; + } + + public String getComponent() { + return component; + } + + public void setComponent(String component) { + this.component = component; + } + + /** + * For use in tests + * + * @param json + * incoming JSON to parse + * @return a node tree + * @throws IOException + * on any parsing problems + */ + public static ContainerNode parse(String json) throws IOException { + ObjectMapper mapper = new ObjectMapper(factory); + JsonNode jsonNode = mapper.readTree(json); + if (!(jsonNode instanceof ContainerNode)) { + throw new IOException("Wrong JSON data: " + json); + } + return (ContainerNode) jsonNode; + } +} http://git-wip-us.apache.org/repos/asf/sentry/blob/9351d19d/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/log/entity/DBAuditMetadataLogEntity.java ---------------------------------------------------------------------- diff --git a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/log/entity/DBAuditMetadataLogEntity.java b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/log/entity/DBAuditMetadataLogEntity.java new file mode 100644 index 0000000..4949ac7 --- /dev/null +++ b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/log/entity/DBAuditMetadataLogEntity.java @@ -0,0 +1,124 @@ +/** + * 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.provider.db.log.entity; + +import java.io.IOException; +import java.io.StringWriter; + +import org.apache.sentry.provider.db.log.util.Constants; +import org.codehaus.jackson.JsonGenerator; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class DBAuditMetadataLogEntity extends AuditMetadataLogEntity { + private static final Logger LOGGER = LoggerFactory.getLogger(DBAuditMetadataLogEntity.class); + + private String databaseName; + private String tableName; + private String columnName; + private String resourcePath; + + public DBAuditMetadataLogEntity() { + } + + public DBAuditMetadataLogEntity(String serviceName, String userName, String impersonator, + String ipAddress, String operation, String eventTime, String operationText, String allowed, + String objectType, String component, String databaseName, String tableName, + String columnName, String resourcePath) { + setCommonAttr(serviceName, userName, impersonator, ipAddress, operation, eventTime, + operationText, allowed, objectType, component); + this.databaseName = databaseName; + this.tableName = tableName; + this.columnName = columnName; + this.resourcePath = resourcePath; + } + + public String getDatabaseName() { + return databaseName; + } + + public void setDatabaseName(String databaseName) { + this.databaseName = databaseName; + } + + public String getTableName() { + return tableName; + } + + public void setTableName(String tableName) { + this.tableName = tableName; + } + + public String getColumnName() { + return columnName; + } + + public void setColumnName(String columnName) { + this.columnName = columnName; + } + + public String getResourcePath() { + return resourcePath; + } + + public void setResourcePath(String resourcePath) { + this.resourcePath = resourcePath; + } + + @Override + public String toJsonFormatLog() throws Exception { + StringWriter stringWriter = new StringWriter(); + JsonGenerator json = null; + try { + json = factory.createJsonGenerator(stringWriter); + json.writeStartObject(); + json.writeStringField(Constants.LOG_FIELD_SERVICE_NAME, getServiceName()); + json.writeStringField(Constants.LOG_FIELD_USER_NAME, getUserName()); + json.writeStringField(Constants.LOG_FIELD_IMPERSONATOR, getImpersonator()); + json.writeStringField(Constants.LOG_FIELD_IP_ADDRESS, getIpAddress()); + json.writeStringField(Constants.LOG_FIELD_OPERATION, getOperation()); + json.writeStringField(Constants.LOG_FIELD_EVENT_TIME, getEventTime()); + json.writeStringField(Constants.LOG_FIELD_OPERATION_TEXT, getOperationText()); + json.writeStringField(Constants.LOG_FIELD_ALLOWED, getAllowed()); + json.writeStringField(Constants.LOG_FIELD_DATABASE_NAME, databaseName); + json.writeStringField(Constants.LOG_FIELD_TABLE_NAME, tableName); + json.writeStringField(Constants.LOG_FIELD_COLUMN_NAME, columnName); + json.writeStringField(Constants.LOG_FIELD_RESOURCE_PATH, resourcePath); + json.writeStringField(Constants.LOG_FIELD_OBJECT_TYPE, getObjectType()); + json.writeEndObject(); + json.flush(); + } catch (IOException e) { + String msg = "Error creating audit log in json format: " + e.getMessage(); + LOGGER.error(msg, e); + throw e; + } finally { + try { + if (json != null) { + json.close(); + } + } catch (IOException e) { + String msg = "Error when close json object: " + e.getMessage(); + LOGGER.error(msg, e); + throw e; + } + } + + return stringWriter.toString(); + } +} http://git-wip-us.apache.org/repos/asf/sentry/blob/9351d19d/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/log/entity/GMAuditMetadataLogEntity.java ---------------------------------------------------------------------- diff --git a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/log/entity/GMAuditMetadataLogEntity.java b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/log/entity/GMAuditMetadataLogEntity.java new file mode 100644 index 0000000..6911772 --- /dev/null +++ b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/log/entity/GMAuditMetadataLogEntity.java @@ -0,0 +1,97 @@ +/** + * 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.provider.db.log.entity; + +import java.io.IOException; +import java.io.StringWriter; +import java.util.LinkedHashMap; +import java.util.Map; + +import org.apache.sentry.provider.db.log.util.Constants; +import org.codehaus.jackson.JsonGenerator; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class GMAuditMetadataLogEntity extends AuditMetadataLogEntity { + + private static final Logger LOGGER = LoggerFactory.getLogger(GMAuditMetadataLogEntity.class); + private Map<String, String> privilegesMap; + + public GMAuditMetadataLogEntity() { + privilegesMap = new LinkedHashMap<String, String>(); + } + + public GMAuditMetadataLogEntity(String serviceName, String userName, String impersonator, + String ipAddress, String operation, String eventTime, String operationText, String allowed, + String objectType, String component, Map<String, String> privilegesMap) { + setCommonAttr(serviceName, userName, impersonator, ipAddress, operation, eventTime, + operationText, allowed, objectType, component); + this.privilegesMap = privilegesMap; + } + + @Override + public String toJsonFormatLog() throws Exception { + StringWriter stringWriter = new StringWriter(); + JsonGenerator json = null; + try { + json = factory.createJsonGenerator(stringWriter); + json.writeStartObject(); + json.writeStringField(Constants.LOG_FIELD_SERVICE_NAME, getServiceName()); + json.writeStringField(Constants.LOG_FIELD_USER_NAME, getUserName()); + json.writeStringField(Constants.LOG_FIELD_IMPERSONATOR, getImpersonator()); + json.writeStringField(Constants.LOG_FIELD_IP_ADDRESS, getIpAddress()); + json.writeStringField(Constants.LOG_FIELD_OPERATION, getOperation()); + json.writeStringField(Constants.LOG_FIELD_EVENT_TIME, getEventTime()); + json.writeStringField(Constants.LOG_FIELD_OPERATION_TEXT, getOperationText()); + json.writeStringField(Constants.LOG_FIELD_ALLOWED, getAllowed()); + for (Map.Entry<String, String> entry : privilegesMap.entrySet()) { + json.writeStringField(entry.getKey(), entry.getValue()); + } + json.writeStringField(Constants.LOG_FIELD_OBJECT_TYPE, getObjectType()); + json.writeStringField(Constants.LOG_FIELD_COMPONENT, getComponent()); + json.writeEndObject(); + json.flush(); + } catch (IOException e) { + String msg = "Error creating audit log in json format: " + e.getMessage(); + LOGGER.error(msg, e); + throw e; + } finally { + try { + if (json != null) { + json.close(); + } + } catch (IOException e) { + String msg = "Error when close json object: " + e.getMessage(); + LOGGER.error(msg, e); + throw e; + } + } + + return stringWriter.toString(); + } + + public Map<String, String> getPrivilegesMap() { + return privilegesMap; + } + + public void setPrivilegesMap(Map<String, String> privilegesMap) { + this.privilegesMap = privilegesMap; + } + +} http://git-wip-us.apache.org/repos/asf/sentry/blob/9351d19d/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/log/entity/JsonLogEntity.java ---------------------------------------------------------------------- diff --git a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/log/entity/JsonLogEntity.java b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/log/entity/JsonLogEntity.java new file mode 100644 index 0000000..913f125 --- /dev/null +++ b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/log/entity/JsonLogEntity.java @@ -0,0 +1,25 @@ +/** + * 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.provider.db.log.entity; + +public interface JsonLogEntity { + + String toJsonFormatLog() throws Exception; + +} http://git-wip-us.apache.org/repos/asf/sentry/blob/9351d19d/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/log/entity/JsonLogEntityFactory.java ---------------------------------------------------------------------- diff --git a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/log/entity/JsonLogEntityFactory.java b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/log/entity/JsonLogEntityFactory.java new file mode 100644 index 0000000..61becce --- /dev/null +++ b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/log/entity/JsonLogEntityFactory.java @@ -0,0 +1,351 @@ +/** + * 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.provider.db.log.entity; + +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.apache.hadoop.conf.Configuration; +import org.apache.sentry.api.generic.thrift.TAuthorizable; +import org.apache.sentry.provider.db.log.util.CommandUtil; +import org.apache.sentry.provider.db.log.util.Constants; +import org.apache.sentry.api.service.thrift.TAlterSentryRoleAddGroupsRequest; +import org.apache.sentry.api.service.thrift.TAlterSentryRoleAddGroupsResponse; +import org.apache.sentry.api.service.thrift.TAlterSentryRoleAddUsersRequest; +import org.apache.sentry.api.service.thrift.TAlterSentryRoleAddUsersResponse; +import org.apache.sentry.api.service.thrift.TAlterSentryRoleDeleteGroupsRequest; +import org.apache.sentry.api.service.thrift.TAlterSentryRoleDeleteGroupsResponse; +import org.apache.sentry.api.service.thrift.TAlterSentryRoleDeleteUsersRequest; +import org.apache.sentry.api.service.thrift.TAlterSentryRoleDeleteUsersResponse; +import org.apache.sentry.api.service.thrift.TAlterSentryRoleGrantPrivilegeRequest; +import org.apache.sentry.api.service.thrift.TAlterSentryRoleGrantPrivilegeResponse; +import org.apache.sentry.api.service.thrift.TAlterSentryRoleRevokePrivilegeRequest; +import org.apache.sentry.api.service.thrift.TAlterSentryRoleRevokePrivilegeResponse; +import org.apache.sentry.api.service.thrift.TCreateSentryRoleRequest; +import org.apache.sentry.api.service.thrift.TCreateSentryRoleResponse; +import org.apache.sentry.api.service.thrift.TDropSentryRoleRequest; +import org.apache.sentry.api.service.thrift.TDropSentryRoleResponse; +import org.apache.sentry.api.service.thrift.TSentryGroup; +import org.apache.sentry.api.service.thrift.TSentryPrivilege; +import org.apache.sentry.core.common.utils.ThriftUtil; +import org.apache.sentry.service.common.ServiceConstants.ServerConfig; +import org.apache.sentry.api.common.Status; +import org.apache.sentry.service.thrift.TSentryResponseStatus; + +import com.google.common.base.Joiner; +import com.google.common.collect.ImmutableSet; + +public final class JsonLogEntityFactory { + + private static JsonLogEntityFactory factory = new JsonLogEntityFactory(); + + private JsonLogEntityFactory() { + } + + public static JsonLogEntityFactory getInstance() { + return factory; + } + + // log entity for hive/impala create role + public JsonLogEntity createJsonLogEntity(TCreateSentryRoleRequest request, + TCreateSentryRoleResponse response, Configuration conf) { + DBAuditMetadataLogEntity hamle = createCommonHAMLE(conf, response.getStatus(), + request.getRequestorUserName(), request.getClass().getName()); + hamle.setOperationText(CommandUtil.createCmdForCreateOrDropRole( + request.getRoleName(), true)); + + return hamle; + } + + // log entity for hive/impala drop role + public JsonLogEntity createJsonLogEntity(TDropSentryRoleRequest request, + TDropSentryRoleResponse response, Configuration conf) { + DBAuditMetadataLogEntity hamle = createCommonHAMLE(conf, response.getStatus(), + request.getRequestorUserName(), request.getClass().getName()); + hamle.setOperationText(CommandUtil.createCmdForCreateOrDropRole( + request.getRoleName(), false)); + + return hamle; + } + + // log entity for hive/impala grant privilege + public Set<JsonLogEntity> createJsonLogEntitys( + TAlterSentryRoleGrantPrivilegeRequest request, + TAlterSentryRoleGrantPrivilegeResponse response, Configuration conf) { + ImmutableSet.Builder<JsonLogEntity> setBuilder = ImmutableSet.builder(); + if (request.isSetPrivileges()) { + for (TSentryPrivilege privilege : request.getPrivileges()) { + JsonLogEntity logEntity = createJsonLogEntity(request, privilege, response, conf); + setBuilder.add(logEntity); + } + } + return setBuilder.build(); + } + + private JsonLogEntity createJsonLogEntity( + TAlterSentryRoleGrantPrivilegeRequest request, TSentryPrivilege privilege, + TAlterSentryRoleGrantPrivilegeResponse response, Configuration conf) { + DBAuditMetadataLogEntity hamle = createCommonHAMLE(conf, response.getStatus(), + request.getRequestorUserName(), request.getClass().getName()); + hamle.setOperationText(CommandUtil.createCmdForGrantPrivilege(request)); + hamle.setDatabaseName(privilege.getDbName()); + hamle.setTableName(privilege.getTableName()); + hamle.setResourcePath(privilege.getURI()); + return hamle; + } + + // log entity for hive/impala revoke privilege + public Set<JsonLogEntity> createJsonLogEntitys( + TAlterSentryRoleRevokePrivilegeRequest request, + TAlterSentryRoleRevokePrivilegeResponse response, Configuration conf) { + ImmutableSet.Builder<JsonLogEntity> setBuilder = ImmutableSet.builder(); + if (request.isSetPrivileges()) { + for (TSentryPrivilege privilege : request.getPrivileges()) { + JsonLogEntity logEntity = createJsonLogEntity(request, privilege, response, conf); + setBuilder.add(logEntity); + } + } + return setBuilder.build(); + } + + private JsonLogEntity createJsonLogEntity( + TAlterSentryRoleRevokePrivilegeRequest request, TSentryPrivilege privilege, + TAlterSentryRoleRevokePrivilegeResponse response, Configuration conf) { + DBAuditMetadataLogEntity hamle = createCommonHAMLE(conf, response.getStatus(), + request.getRequestorUserName(), request.getClass().getName()); + hamle.setOperationText(CommandUtil.createCmdForRevokePrivilege(request)); + hamle.setDatabaseName(privilege.getDbName()); + hamle.setTableName(privilege.getTableName()); + hamle.setResourcePath(privilege.getURI()); + + return hamle; + } + + // log entity for hive/impala add role to group + public JsonLogEntity createJsonLogEntity( + TAlterSentryRoleAddGroupsRequest request, + TAlterSentryRoleAddGroupsResponse response, Configuration conf) { + DBAuditMetadataLogEntity hamle = createCommonHAMLE(conf, response.getStatus(), + request.getRequestorUserName(), request.getClass().getName()); + String groups = getGroupsStr(request.getGroupsIterator()); + hamle.setOperationText(CommandUtil.createCmdForRoleAddGroup(request.getRoleName(), groups)); + + return hamle; + } + + // log entity for hive/impala delete role from group + public JsonLogEntity createJsonLogEntity( + TAlterSentryRoleDeleteGroupsRequest request, + TAlterSentryRoleDeleteGroupsResponse response, Configuration conf) { + DBAuditMetadataLogEntity hamle = createCommonHAMLE(conf, response.getStatus(), + request.getRequestorUserName(), request.getClass().getName()); + String groups = getGroupsStr(request.getGroupsIterator()); + hamle.setOperationText(CommandUtil.createCmdForRoleDeleteGroup(request.getRoleName(), groups)); + + return hamle; + } + + private String getGroupsStr(Iterator<TSentryGroup> iter) { + StringBuilder groups = new StringBuilder(""); + if (iter != null) { + boolean commaFlg = false; + while (iter.hasNext()) { + if (commaFlg) { + groups.append(", "); + } else { + commaFlg = true; + } + groups.append(iter.next().getGroupName()); + } + } + return groups.toString(); + } + + public JsonLogEntity createJsonLogEntity(TAlterSentryRoleAddUsersRequest request, + TAlterSentryRoleAddUsersResponse response, Configuration conf) { + AuditMetadataLogEntity amle = createCommonHAMLE(conf, response.getStatus(), + request.getRequestorUserName(), request.getClass().getName()); + String users = getUsersStr(request.getUsersIterator()); + amle.setOperationText(CommandUtil.createCmdForRoleAddUser(request.getRoleName(), users)); + + return amle; + } + + public JsonLogEntity createJsonLogEntity(TAlterSentryRoleDeleteUsersRequest request, + TAlterSentryRoleDeleteUsersResponse response, Configuration conf) { + AuditMetadataLogEntity amle = createCommonHAMLE(conf, response.getStatus(), + request.getRequestorUserName(), request.getClass().getName()); + String users = getUsersStr(request.getUsersIterator()); + amle.setOperationText(CommandUtil.createCmdForRoleDeleteUser(request.getRoleName(), users)); + + return amle; + } + + private String getUsersStr(Iterator<String> iter) { + StringBuilder users = new StringBuilder(""); + if (iter != null) { + boolean commaFlg = false; + while (iter.hasNext()) { + if (commaFlg) { + users.append(", "); + } else { + commaFlg = true; + } + users.append(iter.next()); + } + } + return users.toString(); + } + + public String isAllowed(TSentryResponseStatus status) { + if (status.equals(Status.OK())) { + return Constants.TRUE; + } + return Constants.FALSE; + } + + // log entity for generic model create role + public JsonLogEntity createJsonLogEntity( + org.apache.sentry.api.generic.thrift.TCreateSentryRoleRequest request, + org.apache.sentry.api.generic.thrift.TCreateSentryRoleResponse response, + Configuration conf) { + GMAuditMetadataLogEntity gmamle = createCommonGMAMLE(conf, response.getStatus(), + request.getRequestorUserName(), request.getClass().getName(), request.getComponent()); + gmamle.setOperationText(CommandUtil.createCmdForCreateOrDropRole(request.getRoleName(), true)); + + return gmamle; + } + + // log entity for generic model drop role + public JsonLogEntity createJsonLogEntity( + org.apache.sentry.api.generic.thrift.TDropSentryRoleRequest request, + org.apache.sentry.api.generic.thrift.TDropSentryRoleResponse response, + Configuration conf) { + GMAuditMetadataLogEntity gmamle = createCommonGMAMLE(conf, response.getStatus(), + request.getRequestorUserName(), request.getClass().getName(), request.getComponent()); + gmamle.setOperationText(CommandUtil.createCmdForCreateOrDropRole(request.getRoleName(), false)); + + return gmamle; + } + + // log entity for generic model grant privilege + public JsonLogEntity createJsonLogEntity( + org.apache.sentry.api.generic.thrift.TAlterSentryRoleGrantPrivilegeRequest request, + org.apache.sentry.api.generic.thrift.TAlterSentryRoleGrantPrivilegeResponse response, + Configuration conf) { + GMAuditMetadataLogEntity gmamle = createCommonGMAMLE(conf, response.getStatus(), + request.getRequestorUserName(), request.getClass().getName(), request.getComponent()); + if (request.getPrivilege() != null) { + List<TAuthorizable> authorizables = request.getPrivilege().getAuthorizables(); + Map<String, String> privilegesMap = new LinkedHashMap<String, String>(); + if (authorizables != null) { + for (TAuthorizable authorizable : authorizables) { + privilegesMap.put(authorizable.getType(), authorizable.getName()); + } + } + gmamle.setPrivilegesMap(privilegesMap); + } + gmamle.setOperationText(CommandUtil.createCmdForGrantGMPrivilege(request)); + + return gmamle; + } + + // log entity for generic model revoke privilege + public JsonLogEntity createJsonLogEntity( + org.apache.sentry.api.generic.thrift.TAlterSentryRoleRevokePrivilegeRequest request, + org.apache.sentry.api.generic.thrift.TAlterSentryRoleRevokePrivilegeResponse response, + Configuration conf) { + GMAuditMetadataLogEntity gmamle = createCommonGMAMLE(conf, response.getStatus(), + request.getRequestorUserName(), request.getClass().getName(), request.getComponent()); + if (request.getPrivilege() != null) { + List<TAuthorizable> authorizables = request.getPrivilege().getAuthorizables(); + Map<String, String> privilegesMap = new LinkedHashMap<String, String>(); + if (authorizables != null) { + for (TAuthorizable authorizable : authorizables) { + privilegesMap.put(authorizable.getType(), authorizable.getName()); + } + } + gmamle.setPrivilegesMap(privilegesMap); + } + gmamle.setOperationText(CommandUtil.createCmdForRevokeGMPrivilege(request)); + + return gmamle; + } + + // log entity for generic model add role to group + public JsonLogEntity createJsonLogEntity( + org.apache.sentry.api.generic.thrift.TAlterSentryRoleAddGroupsRequest request, + org.apache.sentry.api.generic.thrift.TAlterSentryRoleAddGroupsResponse response, + Configuration conf) { + GMAuditMetadataLogEntity gmamle = createCommonGMAMLE(conf, response.getStatus(), + request.getRequestorUserName(), request.getClass().getName(), request.getComponent()); + Joiner joiner = Joiner.on(","); + String groups = joiner.join(request.getGroupsIterator()); + gmamle.setOperationText(CommandUtil.createCmdForRoleAddGroup(request.getRoleName(), groups)); + + return gmamle; + } + + // log entity for hive delete role from group + public JsonLogEntity createJsonLogEntity( + org.apache.sentry.api.generic.thrift.TAlterSentryRoleDeleteGroupsRequest request, + org.apache.sentry.api.generic.thrift.TAlterSentryRoleDeleteGroupsResponse response, + Configuration conf) { + GMAuditMetadataLogEntity gmamle = createCommonGMAMLE(conf, response.getStatus(), + request.getRequestorUserName(), request.getClass().getName(), request.getComponent()); + Joiner joiner = Joiner.on(","); + String groups = joiner.join(request.getGroupsIterator()); + gmamle.setOperationText(CommandUtil.createCmdForRoleDeleteGroup(request.getRoleName(), groups)); + + return gmamle; + } + + private DBAuditMetadataLogEntity createCommonHAMLE(Configuration conf, + TSentryResponseStatus responseStatus, String userName, String requestClassName) { + DBAuditMetadataLogEntity hamle = new DBAuditMetadataLogEntity(); + setCommAttrForAMLE(hamle, conf, responseStatus, userName, requestClassName); + return hamle; + } + + private GMAuditMetadataLogEntity createCommonGMAMLE(Configuration conf, + TSentryResponseStatus responseStatus, String userName, String requestClassName, + String component) { + GMAuditMetadataLogEntity gmamle = new GMAuditMetadataLogEntity(); + setCommAttrForAMLE(gmamle, conf, responseStatus, userName, requestClassName); + gmamle.setComponent(component); + return gmamle; + } + + private void setCommAttrForAMLE(AuditMetadataLogEntity amle, Configuration conf, + TSentryResponseStatus responseStatus, String userName, String requestClassName) { + amle.setUserName(userName); + amle.setServiceName(conf.get(ServerConfig.SENTRY_SERVICE_NAME, + ServerConfig.SENTRY_SERVICE_NAME_DEFAULT).trim()); + amle.setImpersonator(ThriftUtil.getImpersonator()); + amle.setIpAddress(ThriftUtil.getIpAddress()); + amle.setOperation(Constants.requestTypeToOperationMap.get(requestClassName)); + amle.setEventTime(Long.toString(System.currentTimeMillis())); + amle.setAllowed(isAllowed(responseStatus)); + amle.setObjectType(Constants.requestTypeToObjectTypeMap + .get(requestClassName)); + } +} http://git-wip-us.apache.org/repos/asf/sentry/blob/9351d19d/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/log/util/CommandUtil.java ---------------------------------------------------------------------- diff --git a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/log/util/CommandUtil.java b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/log/util/CommandUtil.java new file mode 100644 index 0000000..6479a60 --- /dev/null +++ b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/log/util/CommandUtil.java @@ -0,0 +1,233 @@ +/** + * 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.provider.db.log.util; + +import java.net.InetAddress; +import java.net.NetworkInterface; +import java.util.Enumeration; +import java.util.List; +import java.util.Set; + +import org.apache.sentry.core.model.db.AccessConstants; +import org.apache.sentry.api.generic.thrift.TAuthorizable; +import org.apache.sentry.api.common.ApiConstants.PrivilegeScope; +import org.apache.sentry.api.service.thrift.TAlterSentryRoleGrantPrivilegeRequest; +import org.apache.sentry.api.service.thrift.TAlterSentryRoleRevokePrivilegeRequest; +import org.apache.sentry.api.service.thrift.TSentryGrantOption; +import org.apache.sentry.api.service.thrift.TSentryPrivilege; +import org.datanucleus.util.StringUtils; + +import com.google.common.annotations.VisibleForTesting; + +public final class CommandUtil { + + public CommandUtil() { + // Make constructor private to avoid instantiation + } + + public static String createCmdForCreateOrDropRole(String roleName, + boolean isCreate) { + if (isCreate) { + return "CREATE ROLE " + roleName; + } + return "DROP ROLE " + roleName; + } + + public static String createCmdForRoleAddGroup(String roleName, String groups) { + return createCmdForRoleGrant(roleName, groups, true, true); + } + + public static String createCmdForRoleDeleteGroup(String roleName, String groups) { + return createCmdForRoleGrant(roleName, groups, false, true); + } + + private static String createCmdForRoleGrant(String roleName, String principals, + boolean isGrant, boolean isGroup) { + StringBuilder sb = new StringBuilder(); + if (isGrant) { + sb.append("GRANT ROLE "); + } else { + sb.append("REVOKE ROLE "); + } + sb.append(roleName); + if (isGrant) { + sb.append(" TO "); + } else { + sb.append(" FROM "); + } + + String principalType = isGroup ? "GROUP" : "USER"; + if (!StringUtils.isEmpty(principals)) { + sb.append(principalType).append(" ").append(principals); + } else { + sb = new StringBuilder("Missing " + principalType + " information."); + } + + return sb.toString(); + } + + public static String createCmdForRoleAddUser(String roleName, String users) { + return createCmdForRoleGrant(roleName, users, true, false); + } + + public static String createCmdForRoleDeleteUser(String roleName, String users) { + return createCmdForRoleGrant(roleName, users, false, false); + } + + public static String createCmdForGrantPrivilege( + TAlterSentryRoleGrantPrivilegeRequest request) { + return createCmdForGrantOrRevokePrivileges(request.getRoleName(), + request.getPrivileges(), true); + } + + public static String createCmdForRevokePrivilege( + TAlterSentryRoleRevokePrivilegeRequest request) { + return createCmdForGrantOrRevokePrivileges(request.getRoleName(), + request.getPrivileges(), false); + } + + private static String createCmdForGrantOrRevokePrivileges(String roleName, + Set<TSentryPrivilege> privileges, boolean isGrant) { + StringBuilder sb = new StringBuilder(); + if (privileges != null) { + for (TSentryPrivilege privilege : privileges) { + sb.append(createCmdForGrantOrRevokePrivilege(roleName, privilege, isGrant)); + } + } + return sb.toString(); + } + + private static String createCmdForGrantOrRevokePrivilege(String roleName, + TSentryPrivilege privilege, boolean isGrant) { + StringBuilder sb = new StringBuilder(); + if (isGrant) { + sb.append("GRANT "); + } else { + sb.append("REVOKE "); + } + + String action = privilege.getAction(); + String privilegeScope = privilege.getPrivilegeScope(); + if (AccessConstants.ALL.equalsIgnoreCase(action)) { + sb.append("ALL"); + } else { + if (action != null) { + action = action.toUpperCase(); + } + sb.append(action); + } + + sb.append(" ON ").append(privilege.getPrivilegeScope()).append(" "); + if (PrivilegeScope.DATABASE.name().equalsIgnoreCase(privilegeScope)) { + sb.append(privilege.getDbName()); + } else if (PrivilegeScope.TABLE.name().equalsIgnoreCase(privilegeScope)) { + sb.append(privilege.getTableName()); + } else if (PrivilegeScope.SERVER.name().equalsIgnoreCase(privilegeScope)) { + sb.append(privilege.getServerName()); + } else if (PrivilegeScope.URI.name().equalsIgnoreCase(privilegeScope)) { + sb.append(privilege.getURI()); + } + + if (isGrant) { + sb.append(" TO ROLE "); + } else { + sb.append(" FROM ROLE "); + } + sb.append(roleName); + + if (privilege.getGrantOption() == TSentryGrantOption.TRUE) { + sb.append(" WITH GRANT OPTION"); + } + + return sb.toString(); + } + + public static String createCmdForGrantGMPrivilege( + org.apache.sentry.api.generic.thrift.TAlterSentryRoleGrantPrivilegeRequest request) { + return createCmdForGrantOrRevokeGMPrivilege(request.getRoleName(), request.getPrivilege(), true); + } + + public static String createCmdForRevokeGMPrivilege( + org.apache.sentry.api.generic.thrift.TAlterSentryRoleRevokePrivilegeRequest request) { + return createCmdForGrantOrRevokeGMPrivilege(request.getRoleName(), request.getPrivilege(), + false); + } + + private static String createCmdForGrantOrRevokeGMPrivilege(String roleName, + org.apache.sentry.api.generic.thrift.TSentryPrivilege privilege, + boolean isGrant) { + StringBuilder sb = new StringBuilder(); + if (isGrant) { + sb.append("GRANT "); + } else { + sb.append("REVOKE "); + } + + String action = privilege.getAction(); + if (AccessConstants.ALL.equalsIgnoreCase(action)) { + sb.append("ALL"); + } else { + if (action != null) { + action = action.toUpperCase(); + } + sb.append(action); + } + + sb.append(" ON"); + + List<TAuthorizable> authorizables = privilege.getAuthorizables(); + if (authorizables != null) { + for (TAuthorizable authorizable : authorizables) { + sb.append(" ").append(authorizable.getType()).append(" ").append(authorizable.getName()); + } + } + + if (isGrant) { + sb.append(" TO ROLE "); + } else { + sb.append(" FROM ROLE "); + } + sb.append(roleName); + + if (privilege.getGrantOption() == org.apache.sentry.api.generic.thrift.TSentryGrantOption.TRUE) { + sb.append(" WITH GRANT OPTION"); + } + + return sb.toString(); + } + + // Check if the given IP is one of the local IP. + @VisibleForTesting + public static boolean assertIPInAuditLog(String ipInAuditLog) throws Exception { + if (ipInAuditLog == null) { + return false; + } + Enumeration<NetworkInterface> netInterfaces = NetworkInterface.getNetworkInterfaces(); + while (netInterfaces.hasMoreElements()) { + NetworkInterface ni = netInterfaces.nextElement(); + Enumeration<InetAddress> ips = ni.getInetAddresses(); + while (ips.hasMoreElements()) { + if (ipInAuditLog.indexOf(ips.nextElement().getHostAddress()) != -1) { + return true; + } + } + } + return false; + } +} http://git-wip-us.apache.org/repos/asf/sentry/blob/9351d19d/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/log/util/Constants.java ---------------------------------------------------------------------- diff --git a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/log/util/Constants.java b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/log/util/Constants.java new file mode 100644 index 0000000..6e91f8b --- /dev/null +++ b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/log/util/Constants.java @@ -0,0 +1,116 @@ +/** + * 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.provider.db.log.util; + +import java.util.Map; +import com.google.common.collect.ImmutableMap; + +import org.apache.sentry.api.service.thrift.*; + +public final class Constants { + public static final String AUDIT_LOGGER_NAME = "sentry.hive.authorization.ddl.logger"; + public static final String AUDIT_LOGGER_NAME_GENERIC = "sentry.generic.authorization.ddl.logger"; + + public static final String LOG_FIELD_SERVICE_NAME = "serviceName"; + public static final String LOG_FIELD_USER_NAME = "userName"; + public static final String LOG_FIELD_IMPERSONATOR = "impersonator"; + public static final String LOG_FIELD_IP_ADDRESS = "ipAddress"; + public static final String LOG_FIELD_OPERATION = "operation"; + public static final String LOG_FIELD_EVENT_TIME = "eventTime"; + public static final String LOG_FIELD_OPERATION_TEXT = "operationText"; + public static final String LOG_FIELD_ALLOWED = "allowed"; + public static final String LOG_FIELD_DATABASE_NAME = "databaseName"; + public static final String LOG_FIELD_TABLE_NAME = "tableName"; + public static final String LOG_FIELD_COLUMN_NAME = "column"; + public static final String LOG_FIELD_RESOURCE_PATH = "resourcePath"; + public static final String LOG_FIELD_OBJECT_TYPE = "objectType"; + public static final String LOG_FIELD_COMPONENT = "component"; + + public static final String OPERATION_CREATE_ROLE = "CREATE_ROLE"; + public static final String OPERATION_DROP_ROLE = "DROP_ROLE"; + public static final String OPERATION_ADD_ROLE = "ADD_ROLE_TO_GROUP"; + public static final String OPERATION_DELETE_ROLE = "DELETE_ROLE_FROM_GROUP"; + public static final String OPERATION_ADD_ROLE_USER = "ADD_ROLE_TO_USER"; + public static final String OPERATION_DELETE_ROLE_USER = "DELETE_ROLE_FROM_USER"; + public static final String OPERATION_GRANT_PRIVILEGE = "GRANT_PRIVILEGE"; + public static final String OPERATION_REVOKE_PRIVILEGE = "REVOKE_PRIVILEGE"; + + public static final String OBJECT_TYPE_PRINCIPAL = "PRINCIPAL"; + public static final String OBJECT_TYPE_ROLE = "ROLE"; + + public static final String TRUE = "true"; + public static final String FALSE = "false"; + + public static final Map<String, String> requestTypeToOperationMap = ImmutableMap.<String, String>builder() + // for hive audit log + .put(TCreateSentryRoleRequest.class.getName(), Constants.OPERATION_CREATE_ROLE) + .put(TAlterSentryRoleGrantPrivilegeRequest.class.getName(), Constants.OPERATION_GRANT_PRIVILEGE) + .put(TAlterSentryRoleRevokePrivilegeRequest.class.getName(), Constants.OPERATION_REVOKE_PRIVILEGE) + .put(TDropSentryRoleRequest.class.getName(), Constants.OPERATION_DROP_ROLE) + .put(TAlterSentryRoleAddGroupsRequest.class.getName(), Constants.OPERATION_ADD_ROLE) + .put(TAlterSentryRoleDeleteGroupsRequest.class.getName(), Constants.OPERATION_DELETE_ROLE) + .put(TAlterSentryRoleAddUsersRequest.class.getName(), Constants.OPERATION_ADD_ROLE_USER) + .put(TAlterSentryRoleDeleteUsersRequest.class.getName(), Constants.OPERATION_DELETE_ROLE_USER) + + // for generic model audit log + .put(org.apache.sentry.api.generic.thrift.TCreateSentryRoleRequest.class.getName(), + Constants.OPERATION_CREATE_ROLE) + .put(org.apache.sentry.api.generic.thrift.TDropSentryRoleRequest.class.getName(), + Constants.OPERATION_DROP_ROLE) + .put(org.apache.sentry.api.generic.thrift.TAlterSentryRoleGrantPrivilegeRequest.class.getName(), + Constants.OPERATION_GRANT_PRIVILEGE) + .put(org.apache.sentry.api.generic.thrift.TAlterSentryRoleRevokePrivilegeRequest.class.getName(), + Constants.OPERATION_REVOKE_PRIVILEGE) + .put(org.apache.sentry.api.generic.thrift.TAlterSentryRoleAddGroupsRequest.class.getName(), + Constants.OPERATION_ADD_ROLE) + .put(org.apache.sentry.api.generic.thrift.TAlterSentryRoleDeleteGroupsRequest.class.getName(), + Constants.OPERATION_DELETE_ROLE) + .build(); + + public static final Map<String, String> requestTypeToObjectTypeMap = ImmutableMap.<String, String>builder() + // for hive audit log + .put(TCreateSentryRoleRequest.class.getName(), Constants.OBJECT_TYPE_ROLE) + .put(TDropSentryRoleRequest.class.getName(), Constants.OBJECT_TYPE_ROLE) + .put(TAlterSentryRoleAddGroupsRequest.class.getName(), Constants.OBJECT_TYPE_ROLE) + .put(TAlterSentryRoleDeleteGroupsRequest.class.getName(), Constants.OBJECT_TYPE_ROLE) + .put(TAlterSentryRoleAddUsersRequest.class.getName(), Constants.OBJECT_TYPE_ROLE) + .put(TAlterSentryRoleDeleteUsersRequest.class.getName(), Constants.OBJECT_TYPE_ROLE) + .put(TAlterSentryRoleGrantPrivilegeRequest.class.getName(), Constants.OBJECT_TYPE_PRINCIPAL) + .put(TAlterSentryRoleRevokePrivilegeRequest.class.getName(), Constants.OBJECT_TYPE_PRINCIPAL) + + // for generic model audit log + .put(org.apache.sentry.api.generic.thrift.TCreateSentryRoleRequest.class.getName(), + Constants.OBJECT_TYPE_ROLE) + .put(org.apache.sentry.api.generic.thrift.TDropSentryRoleRequest.class.getName(), + Constants.OBJECT_TYPE_ROLE) + .put(org.apache.sentry.api.generic.thrift.TAlterSentryRoleAddGroupsRequest.class.getName(), + Constants.OBJECT_TYPE_ROLE) + .put(org.apache.sentry.api.generic.thrift.TAlterSentryRoleDeleteGroupsRequest.class.getName(), + Constants.OBJECT_TYPE_ROLE) + .put(org.apache.sentry.api.generic.thrift.TAlterSentryRoleGrantPrivilegeRequest.class.getName(), + Constants.OBJECT_TYPE_PRINCIPAL) + .put(org.apache.sentry.api.generic.thrift.TAlterSentryRoleRevokePrivilegeRequest.class.getName(), + Constants.OBJECT_TYPE_PRINCIPAL) + .build(); + + private Constants() { + // Make constructor private to avoid instantiation + } + +} http://git-wip-us.apache.org/repos/asf/sentry/blob/9351d19d/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/model/MAuthzPathsMapping.java ---------------------------------------------------------------------- diff --git a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/model/MAuthzPathsMapping.java b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/model/MAuthzPathsMapping.java new file mode 100644 index 0000000..c51f25a --- /dev/null +++ b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/model/MAuthzPathsMapping.java @@ -0,0 +1,147 @@ +/** + * 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.provider.db.service.model; + +import javax.jdo.annotations.PersistenceCapable; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; + +/** + * Transactional database backend for storing HMS Paths Updates. Any changes to this object + * require re-running the maven build so DN can re-enhance. + */ +@PersistenceCapable +public class MAuthzPathsMapping { + + private long authzSnapshotID; + private String authzObjName; + private Set<MPath> paths; + private long createTimeMs; + + public MAuthzPathsMapping(long authzSnapshotID, String authzObjName, Collection<String> paths) { + this.authzSnapshotID = authzSnapshotID; + this.authzObjName = MSentryUtil.safeIntern(authzObjName); + this.paths = new HashSet<>(paths.size()); + for (String path : paths) { + this.paths.add(new MPath(path)); + } + this.createTimeMs = System.currentTimeMillis(); + } + + public long getCreateTime() { + return createTimeMs; + } + + public void setCreateTime(long createTime) { + this.createTimeMs = createTime; + } + + public String getAuthzObjName() { + return authzObjName; + } + + public void setAuthzObjName(String authzObjName) { + this.authzObjName = authzObjName; + } + + public void setPaths(Set<MPath> paths) { + this.paths = paths; + } + + public Set<MPath> getPaths() { + return paths; + } + + public boolean removePath(MPath path) { + return paths.remove(path); + } + + public void addPath(MPath path) { + paths.add(path); + } + + /** + * Gets MPath object that has the given path value. + * TODO: Try to avoid loop lookup in future for performance improvement. + * + * @param path the given path name + * @return an Path object that has the given path value. + */ + public MPath getPath(String path) { + for (MPath mPath : paths) { + if (mPath.getPath().equals(path)) { + return mPath; + } + } + return null; + } + + /** + * @return collection of paths strings contained in this object. + */ + public Collection<String> getPathStrings() { + Collection<String> pathValues = new ArrayList<>(this.paths.size()); + for (MPath path : this.paths) { + pathValues.add(path.getPath()); + } + return pathValues; + } + + @Override + public String toString() { + return "MSentryPathsUpdate authzSnapshotID=[" + authzSnapshotID + "], authzObj=[" + authzObjName + + "], paths=[" + paths.toString() + "], createTimeMs=[" + createTimeMs + "]"; + } + + @Override + public int hashCode() { + return authzObjName == null ? 0 : authzObjName.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + + if (obj == null) { + return false; + } + + if (getClass() != obj.getClass()) { + return false; + } + + MAuthzPathsMapping other = (MAuthzPathsMapping) obj; + + if (authzObjName == null) { + if (other.authzObjName != null) { + return false; + } + } else if (!authzObjName.equals(other.authzObjName)) { + return false; + } else if (authzSnapshotID != other.authzSnapshotID) { + return false; + } + + return true; + } +} http://git-wip-us.apache.org/repos/asf/sentry/blob/9351d19d/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/model/MAuthzPathsSnapshotId.java ---------------------------------------------------------------------- diff --git a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/model/MAuthzPathsSnapshotId.java b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/model/MAuthzPathsSnapshotId.java new file mode 100644 index 0000000..d683c2c --- /dev/null +++ b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/model/MAuthzPathsSnapshotId.java @@ -0,0 +1,63 @@ +/** + * 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.provider.db.service.model; + +import javax.jdo.annotations.PersistenceCapable; +import javax.jdo.annotations.PrimaryKey; + +/** + * This class is used to persist new authz paths snapshots IDs. An authz path snapshot ID is required by + * the MAuthzPathsMapping to detect new HMS snapshots created by the HMSFollower. + */ +@PersistenceCapable +public class MAuthzPathsSnapshotId { + @PrimaryKey + private long authzSnapshotID; + + public MAuthzPathsSnapshotId(long authzSnapshotID) { + this.authzSnapshotID = authzSnapshotID; + } + + @Override + public String toString() { + return "MAuthzPathsSnapshotId authzSnapshotID=[" + authzSnapshotID + "]"; + } + + @Override + public int hashCode() { + return (int)authzSnapshotID; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + + if (obj == null) { + return false; + } + + if (getClass() != obj.getClass()) { + return false; + } + + MAuthzPathsSnapshotId other = (MAuthzPathsSnapshotId) obj; + return (authzSnapshotID == other.authzSnapshotID); + } +} http://git-wip-us.apache.org/repos/asf/sentry/blob/9351d19d/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/model/MPath.java ---------------------------------------------------------------------- diff --git a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/model/MPath.java b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/model/MPath.java new file mode 100644 index 0000000..b0eaff2 --- /dev/null +++ b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/model/MPath.java @@ -0,0 +1,69 @@ +/* + * 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.provider.db.service.model; + +/** + * Used to store the path for the Authorizable object + * + * New class is created for path in order to have 1 to many mapping + * between path and Authorizable object. + */ +public class MPath { + private String path; + + public MPath(String path) { + this.path = MSentryUtil.safeIntern(path); + } + + public String getPath() { + return path; + } + + public void setPath(String path) { this.path = path; } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((path == null) ? 0 : path.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + + if (obj == null) { + return false; + } + + if (getClass() != obj.getClass()) { + return false; + } + + MPath other = (MPath) obj; + + if (path == null) { + return other.path == null; + } + + return path.equals(other.path); + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/sentry/blob/9351d19d/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/model/MSentryChange.java ---------------------------------------------------------------------- diff --git a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/model/MSentryChange.java b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/model/MSentryChange.java new file mode 100644 index 0000000..9b022a1 --- /dev/null +++ b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/model/MSentryChange.java @@ -0,0 +1,25 @@ +/** + * 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.provider.db.service.model; + +/** + * The base class for various delta changes stored in Sentry DB. + */ +public interface MSentryChange { + long getChangeID(); +} http://git-wip-us.apache.org/repos/asf/sentry/blob/9351d19d/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/model/MSentryGMPrivilege.java ---------------------------------------------------------------------- diff --git a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/model/MSentryGMPrivilege.java b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/model/MSentryGMPrivilege.java new file mode 100644 index 0000000..24ed204 --- /dev/null +++ b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/model/MSentryGMPrivilege.java @@ -0,0 +1,436 @@ +/** + * 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.provider.db.service.model; + +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.Field; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Set; + +import javax.jdo.annotations.PersistenceCapable; +import org.apache.sentry.core.common.Authorizable; +import org.apache.sentry.core.model.db.AccessConstants; + +import com.google.common.base.Strings; +import com.google.common.collect.Lists; + +/** + * Database backed Sentry Generic Privilege for new authorization Model + * Any changes to this object + * require re-running the maven build so DN an re-enhance. + */ +@PersistenceCapable +public class MSentryGMPrivilege { + public static final String PREFIX_RESOURCE_NAME = "resourceName"; + public static final String PREFIX_RESOURCE_TYPE = "resourceType"; + public static final int AUTHORIZABLE_LEVEL = 4; + + private static final String NULL_COL = "__NULL__"; + private static final String SERVICE_SCOPE = "Server"; + + /** + * The authorizable List has been stored into resourceName and resourceField columns + * We assume that the generic model privilege for any component(hive/impala or solr) doesn't exceed four level. + * This generic model privilege currently can support maximum 4 level. + **/ + private String resourceName0 = NULL_COL; //NOPMD + private String resourceType0 = NULL_COL; //NOPMD + private String resourceName1 = NULL_COL; //NOPMD + private String resourceType1 = NULL_COL; //NOPMD + private String resourceName2 = NULL_COL; //NOPMD + private String resourceType2 = NULL_COL; //NOPMD + private String resourceName3 = NULL_COL; //NOPMD + private String resourceType3 = NULL_COL; //NOPMD + + + private String serviceName; + private String componentName; + private String action; + private String scope; + + private Boolean grantOption = false; + // roles this privilege is a part of + private Set<MSentryRole> roles; + private long createTime; + + public MSentryGMPrivilege() { + this.roles = new HashSet<MSentryRole>(); + } + + public MSentryGMPrivilege(String componentName, String serviceName, + List<? extends Authorizable> authorizables, + String action, Boolean grantOption) { + this.componentName = MSentryUtil.safeIntern(componentName); + this.serviceName = MSentryUtil.safeIntern(serviceName); + this.action = MSentryUtil.safeIntern(action); + this.grantOption = grantOption; + this.roles = new HashSet<>(); + this.createTime = System.currentTimeMillis(); + setAuthorizables(authorizables); + } + + public MSentryGMPrivilege(MSentryGMPrivilege copy) { + this.action = copy.action; + this.componentName = copy.componentName; + this.serviceName = copy.serviceName; + this.grantOption = copy.grantOption; + this.scope = copy.scope; + this.createTime = copy.createTime; + setAuthorizables(copy.getAuthorizables()); + this.roles = new HashSet<MSentryRole>(); + roles.addAll(copy.roles); + } + + public String getServiceName() { + return serviceName; + } + + public void setServiceName(String serviceName) { + this.serviceName = serviceName; + } + + public String getComponentName() { + return componentName; + } + + public void setComponentName(String componentName) { + this.componentName = componentName; + } + + public String getAction() { + return action; + } + + public void setAction(String action) { + this.action = action; + } + + public Boolean getGrantOption() { + return grantOption; + } + + public void setGrantOption(Boolean grantOption) { + this.grantOption = grantOption; + } + + public Set<MSentryRole> getRoles() { + return roles; + } + + public void setRoles(Set<MSentryRole> roles) { + this.roles = roles; + } + + public long getCreateTime() { + return createTime; + } + + public void setCreateTime(long createTime) { + this.createTime = createTime; + } + + public String getScope() { + return scope; + } + + public List<? extends Authorizable> getAuthorizables() { + List<Authorizable> authorizables = Lists.newArrayList(); + //construct atuhorizable lists + for (int i = 0; i < AUTHORIZABLE_LEVEL; i++) { + final String resourceName = (String) getField(this, PREFIX_RESOURCE_NAME + String.valueOf(i)); + final String resourceTYpe = (String) getField(this, PREFIX_RESOURCE_TYPE + String.valueOf(i)); + + if (notNULL(resourceName) && notNULL(resourceTYpe)) { + authorizables.add(new Authorizable() { + @Override + public String getTypeName() { + return resourceTYpe; + } + @Override + public String getName() { + return resourceName; + } + }); + } + } + return authorizables; + } + + /** + * Only allow strict hierarchies. That is, can level =1 be not null when level = 0 is null + * @param authorizables + */ + public void setAuthorizables(List<? extends Authorizable> authorizables) { + if (authorizables == null || authorizables.isEmpty()) { + //service scope + scope = SERVICE_SCOPE; + return; + } + if (authorizables.size() > AUTHORIZABLE_LEVEL) { + throw new IllegalStateException("This generic privilege model only supports maximum 4 level."); + } + + for (int i = 0; i < authorizables.size(); i++) { + Authorizable authorizable = authorizables.get(i); + if (authorizable == null) { + String msg = String.format("The authorizable can't be null. Please check authorizables[%d]:", i); + throw new IllegalStateException(msg); + } + String resourceName = authorizable.getName(); + String resourceTYpe = authorizable.getTypeName(); + if (isNULL(resourceName) || isNULL(resourceTYpe)) { + String msg = String.format("The name and type of authorizable can't be empty or null.Please check authorizables[%d]", i); + throw new IllegalStateException(msg); + } + setField(this, PREFIX_RESOURCE_NAME + String.valueOf(i), toNULLCol(resourceName)); + setField(this, PREFIX_RESOURCE_TYPE + String.valueOf(i), toNULLCol(resourceTYpe)); + scope = resourceTYpe; + } + } + + public void appendRole(MSentryRole role) { + if (roles.add(role)) { + role.appendGMPrivilege(this); + } + } + + public void removeRole(MSentryRole role) { + if(roles.remove(role)) { + role.removeGMPrivilege(this); + } + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((action == null) ? 0 : action.hashCode()); + result = prime * result + ((componentName == null) ? 0 : componentName.hashCode()); + result = prime * result + ((serviceName == null) ? 0 : serviceName.hashCode()); + result = prime * result + ((grantOption == null) ? 0 : grantOption.hashCode()); + result = prime * result + ((scope == null) ? 0 : scope.hashCode()); + + for (Authorizable authorizable : getAuthorizables()) { + result = prime * result + authorizable.getName().hashCode(); + result = prime * result + authorizable.getTypeName().hashCode(); + } + + return result; + } + + @Override + public String toString() { + List<String> unifiedNames = Lists.newArrayList(); + for (Authorizable auth : getAuthorizables()) { + unifiedNames.add(KV_JOINER.join(auth.getTypeName(),auth.getName())); + } + + return "MSentryGMPrivilege [" + + "serverName=" + serviceName + ", componentName=" + componentName + + ", authorizables=" + AUTHORIZABLE_JOINER.join(unifiedNames)+ ", scope=" + scope + + ", action=" + action + ", roles=[...]" + ", createTime=" + + createTime + ", grantOption=" + grantOption +"]"; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + MSentryGMPrivilege other = (MSentryGMPrivilege) obj; + if (action == null) { + if (other.action != null) { + return false; + } + } else if (!action.equalsIgnoreCase(other.action)) { + return false; + } + if (scope == null) { + if (other.scope != null) { + return false; + } + } else if (!scope.equals(other.scope)) { + return false; + } + if (serviceName == null) { + if (other.serviceName != null) { + return false; + } + } else if (!serviceName.equals(other.serviceName)) { + return false; + } + if (componentName == null) { + if (other.componentName != null) { + return false; + } + } else if (!componentName.equals(other.componentName)) { + return false; + } + if (grantOption == null) { + if (other.grantOption != null) { + return false; + } + } else if (!grantOption.equals(other.grantOption)) { + return false; + } + + List<? extends Authorizable> authorizables = getAuthorizables(); + List<? extends Authorizable> otherAuthorizables = other.getAuthorizables(); + + if (authorizables.size() != otherAuthorizables.size()) { + return false; + } + for (int i = 0; i < authorizables.size(); i++) { + String o1 = KV_JOINER.join(authorizables.get(i).getTypeName(), + authorizables.get(i).getName()); + String o2 = KV_JOINER.join(otherAuthorizables.get(i).getTypeName(), + otherAuthorizables.get(i).getName()); + if (!o1.equals(o2)) { + return false; + } + } + return true; + } + + /** + * Return true if this privilege implies request privilege + * Otherwise, return false + * @param request, other privilege + */ + public boolean implies(MSentryGMPrivilege request) { + //component check + if (!componentName.equals(request.getComponentName())) { + return false; + } + //service check + if (!serviceName.equals(request.getServiceName())) { + return false; + } + // check action implies + if (!action.equalsIgnoreCase(AccessConstants.ALL) + && !action.equalsIgnoreCase(request.getAction()) + && !action.equalsIgnoreCase(AccessConstants.ACTION_ALL)) { + return false; + } + //check authorizable list implies + Iterator<? extends Authorizable> existIterator = getAuthorizables().iterator(); + Iterator<? extends Authorizable> requestIterator = request.getAuthorizables().iterator(); + while (existIterator.hasNext() && requestIterator.hasNext()) { + Authorizable existAuth = existIterator.next(); + Authorizable requestAuth = requestIterator.next(); + //check authorizable type + if (!existAuth.getTypeName().equals(requestAuth.getTypeName())) { + return false; + } + //check authorizable name + if (!existAuth.getName().equals(requestAuth.getName())) { + /**The persistent authorizable isn't equal the request authorizable + * but the following situations are pass check + * The name of persistent authorizable is ALL or "*" + */ + if (existAuth.getName().equalsIgnoreCase(AccessConstants.ACTION_ALL) + || existAuth.getName().equalsIgnoreCase(AccessConstants.ALL)) { + continue; + } else { + return false; + } + } + } + + if ( !existIterator.hasNext() && !requestIterator.hasNext() ){ + /** + * The persistent privilege has the same authorizables size as the requested privilege + * The check is pass + */ + return true; + + } else if (existIterator.hasNext()) { + /** + * The persistent privilege has much more authorizables than request privilege,so its scope is less + * than the requested privilege. + * There is a situation that the check is pass, the name of the exceeding authorizables is ALL or "*". + * Take the Solr for example,the exist privilege is collection=c1->field=*->action=query + * the request privilege is collection=c1->action=query, the check is pass + */ + while (existIterator.hasNext()) { + Authorizable existAuthorizable = existIterator.next(); + if (existAuthorizable.getName().equalsIgnoreCase(AccessConstants.ALL) + || existAuthorizable.getName().equalsIgnoreCase(AccessConstants.ACTION_ALL)) { + continue; + } else { + return false; + } + } + } else { + /** + * The requested privilege has much more authorizables than persistent privilege, so its scope is less + * than the persistent privilege + * The check is pass + */ + return true; + } + + return true; + } + + public static String toNULLCol(String col) { + return Strings.isNullOrEmpty(col) ? NULL_COL : col; + } + + public static boolean notNULL(String s) { + return !(Strings.isNullOrEmpty(s) || NULL_COL.equals(s)); + } + + public static boolean isNULL(String s) { + return !notNULL(s); + } + + public static <T> void setField(Object obj, String fieldName, T fieldValue) { + try { + Class<?> clazz = obj.getClass(); + Field field=clazz.getDeclaredField(fieldName); + field.setAccessible(true); + field.set(obj, fieldValue); + } catch (Exception e) { + throw new RuntimeException("setField error: " + e.getMessage(), e); + } + } + + @SuppressWarnings("unchecked") + public static <T> T getField(Object obj, String fieldName) { + try { + Class<?> clazz = obj.getClass(); + Field field=clazz.getDeclaredField(fieldName); + field.setAccessible(true); + return (T)field.get(obj); + } catch (Exception e) { + throw new RuntimeException("getField error: " + e.getMessage(), e); + } + } + +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/sentry/blob/9351d19d/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/model/MSentryGroup.java ---------------------------------------------------------------------- diff --git a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/model/MSentryGroup.java b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/model/MSentryGroup.java new file mode 100644 index 0000000..e0db741 --- /dev/null +++ b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/model/MSentryGroup.java @@ -0,0 +1,112 @@ +/** + * 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.provider.db.service.model; + +import java.util.Set; + +import javax.jdo.annotations.PersistenceCapable; + +/** + * Database backed Sentry Group. Any changes to this object + * require re-running the maven build so DN an re-enhance. + */ +@PersistenceCapable +public class MSentryGroup { + + /** + * Group name is unique + */ + private String groupName; + // set of roles granted to this group + private Set<MSentryRole> roles; + private long createTime; + + public MSentryGroup(String groupName, long createTime, Set<MSentryRole> roles) { + this.groupName = MSentryUtil.safeIntern(groupName); + this.createTime = createTime; + this.roles = roles; + } + + public long getCreateTime() { + return createTime; + } + + public void setCreateTime(long createTime) { + this.createTime = createTime; + } + + public Set<MSentryRole> getRoles() { + return roles; + } + + public String getGroupName() { + return groupName; + } + + public void appendRole(MSentryRole role) { + if (roles.add(role)) { + role.appendGroup(this); + } + } + + public void removeRole(MSentryRole role) { + if (roles.remove(role)) { + role.removeGroup(this); + } + } + + @Override + public String toString() { + return "MSentryGroup [groupName=" + groupName + ", roles=[...]" + + ", createTime=" + createTime + "]"; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((groupName == null) ? 0 : groupName.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + MSentryGroup other = (MSentryGroup) obj; + if (createTime != other.createTime) { + return false; + } + if (groupName == null) { + if (other.groupName != null) { + return false; + } + } else if (!groupName.equals(other.groupName)) { + return false; + } + return true; + } +}
