http://git-wip-us.apache.org/repos/asf/sentry/blob/b97f5c7a/sentry-service/sentry-service-server/src/main/java/org/apache/sentry/provider/db/log/entity/GMAuditMetadataLogEntity.java ---------------------------------------------------------------------- diff --git a/sentry-service/sentry-service-server/src/main/java/org/apache/sentry/provider/db/log/entity/GMAuditMetadataLogEntity.java b/sentry-service/sentry-service-server/src/main/java/org/apache/sentry/provider/db/log/entity/GMAuditMetadataLogEntity.java new file mode 100644 index 0000000..6911772 --- /dev/null +++ b/sentry-service/sentry-service-server/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/b97f5c7a/sentry-service/sentry-service-server/src/main/java/org/apache/sentry/provider/db/log/entity/JsonLogEntity.java ---------------------------------------------------------------------- diff --git a/sentry-service/sentry-service-server/src/main/java/org/apache/sentry/provider/db/log/entity/JsonLogEntity.java b/sentry-service/sentry-service-server/src/main/java/org/apache/sentry/provider/db/log/entity/JsonLogEntity.java new file mode 100644 index 0000000..913f125 --- /dev/null +++ b/sentry-service/sentry-service-server/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/b97f5c7a/sentry-service/sentry-service-server/src/main/java/org/apache/sentry/provider/db/log/entity/JsonLogEntityFactory.java ---------------------------------------------------------------------- diff --git a/sentry-service/sentry-service-server/src/main/java/org/apache/sentry/provider/db/log/entity/JsonLogEntityFactory.java b/sentry-service/sentry-service-server/src/main/java/org/apache/sentry/provider/db/log/entity/JsonLogEntityFactory.java new file mode 100644 index 0000000..61becce --- /dev/null +++ b/sentry-service/sentry-service-server/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/b97f5c7a/sentry-service/sentry-service-server/src/main/java/org/apache/sentry/provider/db/log/util/CommandUtil.java ---------------------------------------------------------------------- diff --git a/sentry-service/sentry-service-server/src/main/java/org/apache/sentry/provider/db/log/util/CommandUtil.java b/sentry-service/sentry-service-server/src/main/java/org/apache/sentry/provider/db/log/util/CommandUtil.java new file mode 100644 index 0000000..6479a60 --- /dev/null +++ b/sentry-service/sentry-service-server/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/b97f5c7a/sentry-service/sentry-service-server/src/main/java/org/apache/sentry/provider/db/log/util/Constants.java ---------------------------------------------------------------------- diff --git a/sentry-service/sentry-service-server/src/main/java/org/apache/sentry/provider/db/log/util/Constants.java b/sentry-service/sentry-service-server/src/main/java/org/apache/sentry/provider/db/log/util/Constants.java new file mode 100644 index 0000000..6e91f8b --- /dev/null +++ b/sentry-service/sentry-service-server/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/b97f5c7a/sentry-service/sentry-service-server/src/main/java/org/apache/sentry/provider/db/service/model/MAuthzPathsMapping.java ---------------------------------------------------------------------- diff --git a/sentry-service/sentry-service-server/src/main/java/org/apache/sentry/provider/db/service/model/MAuthzPathsMapping.java b/sentry-service/sentry-service-server/src/main/java/org/apache/sentry/provider/db/service/model/MAuthzPathsMapping.java new file mode 100644 index 0000000..c51f25a --- /dev/null +++ b/sentry-service/sentry-service-server/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/b97f5c7a/sentry-service/sentry-service-server/src/main/java/org/apache/sentry/provider/db/service/model/MAuthzPathsSnapshotId.java ---------------------------------------------------------------------- diff --git a/sentry-service/sentry-service-server/src/main/java/org/apache/sentry/provider/db/service/model/MAuthzPathsSnapshotId.java b/sentry-service/sentry-service-server/src/main/java/org/apache/sentry/provider/db/service/model/MAuthzPathsSnapshotId.java new file mode 100644 index 0000000..d683c2c --- /dev/null +++ b/sentry-service/sentry-service-server/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/b97f5c7a/sentry-service/sentry-service-server/src/main/java/org/apache/sentry/provider/db/service/model/MPath.java ---------------------------------------------------------------------- diff --git a/sentry-service/sentry-service-server/src/main/java/org/apache/sentry/provider/db/service/model/MPath.java b/sentry-service/sentry-service-server/src/main/java/org/apache/sentry/provider/db/service/model/MPath.java new file mode 100644 index 0000000..b0eaff2 --- /dev/null +++ b/sentry-service/sentry-service-server/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/b97f5c7a/sentry-service/sentry-service-server/src/main/java/org/apache/sentry/provider/db/service/model/MSentryChange.java ---------------------------------------------------------------------- diff --git a/sentry-service/sentry-service-server/src/main/java/org/apache/sentry/provider/db/service/model/MSentryChange.java b/sentry-service/sentry-service-server/src/main/java/org/apache/sentry/provider/db/service/model/MSentryChange.java new file mode 100644 index 0000000..9b022a1 --- /dev/null +++ b/sentry-service/sentry-service-server/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/b97f5c7a/sentry-service/sentry-service-server/src/main/java/org/apache/sentry/provider/db/service/model/MSentryGMPrivilege.java ---------------------------------------------------------------------- diff --git a/sentry-service/sentry-service-server/src/main/java/org/apache/sentry/provider/db/service/model/MSentryGMPrivilege.java b/sentry-service/sentry-service-server/src/main/java/org/apache/sentry/provider/db/service/model/MSentryGMPrivilege.java new file mode 100644 index 0000000..24ed204 --- /dev/null +++ b/sentry-service/sentry-service-server/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/b97f5c7a/sentry-service/sentry-service-server/src/main/java/org/apache/sentry/provider/db/service/model/MSentryGroup.java ---------------------------------------------------------------------- diff --git a/sentry-service/sentry-service-server/src/main/java/org/apache/sentry/provider/db/service/model/MSentryGroup.java b/sentry-service/sentry-service-server/src/main/java/org/apache/sentry/provider/db/service/model/MSentryGroup.java new file mode 100644 index 0000000..e0db741 --- /dev/null +++ b/sentry-service/sentry-service-server/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; + } +} http://git-wip-us.apache.org/repos/asf/sentry/blob/b97f5c7a/sentry-service/sentry-service-server/src/main/java/org/apache/sentry/provider/db/service/model/MSentryHmsNotification.java ---------------------------------------------------------------------- diff --git a/sentry-service/sentry-service-server/src/main/java/org/apache/sentry/provider/db/service/model/MSentryHmsNotification.java b/sentry-service/sentry-service-server/src/main/java/org/apache/sentry/provider/db/service/model/MSentryHmsNotification.java new file mode 100644 index 0000000..34180e7 --- /dev/null +++ b/sentry-service/sentry-service-server/src/main/java/org/apache/sentry/provider/db/service/model/MSentryHmsNotification.java @@ -0,0 +1,79 @@ +/* + * 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; + +/** + * Database backend store for HMS Notification ID's. All the notifications that are processed + * by sentry are stored. + * <p> + * <p> HMS notification ID's are stored in separate table for three reasons</p> + * <ol> + * <li>SENTRY_PATH_CHANGE is not updated for every notification that is received from HMS. There + * are cases where HMSFollower doesn't process notifications and skip's them. Depending on + * SENTRY_PATH_CHANGE information may not provide the last notification processed.</li> + * <li> There could be cases where HMSFollower thread in multiple sentry servers acting as a + * leader and process HMS notifications. we need to avoid processing the notifications + * multiple times. This can be made sure by always having some number of notification + * information always regardless of purging interval.</li> + * <li>SENTRY_PATH_CHANGE information stored can typically be removed once namenode plug-in + * has processed the update.</li> + * </ol> + * <p> + * As the purpose and usage of notification ID information is different from PATH update info, + * it locally makes sense to store notification ID separately. + * </p> + */ +public class MSentryHmsNotification { + private long notificationId; + + public MSentryHmsNotification(long notificationId) { + this.notificationId = notificationId; + } + + public long getId() { + return notificationId; + } + + public void setId(long notificationId) { + this.notificationId = notificationId; + } + + @Override + public int hashCode() { + return (int) notificationId; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + + if (obj == null) { + return false; + } + + if (getClass() != obj.getClass()) { + return false; + } + + MSentryHmsNotification other = (MSentryHmsNotification) obj; + + return (notificationId == other.notificationId); + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/sentry/blob/b97f5c7a/sentry-service/sentry-service-server/src/main/java/org/apache/sentry/provider/db/service/model/MSentryPathChange.java ---------------------------------------------------------------------- diff --git a/sentry-service/sentry-service-server/src/main/java/org/apache/sentry/provider/db/service/model/MSentryPathChange.java b/sentry-service/sentry-service-server/src/main/java/org/apache/sentry/provider/db/service/model/MSentryPathChange.java new file mode 100644 index 0000000..bb5ff21 --- /dev/null +++ b/sentry-service/sentry-service-server/src/main/java/org/apache/sentry/provider/db/service/model/MSentryPathChange.java @@ -0,0 +1,157 @@ +/** + * 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 org.apache.sentry.hdfs.PathsUpdate; +import org.apache.thrift.TException; + +import javax.jdo.annotations.PersistenceCapable; +import javax.jdo.annotations.PrimaryKey; + +/** + * Database backend store for HMS path delta change. Each record contains + * change ID, HMS notification ID, JSON format of a single + * < Hive Obj, HDFS Path > change, and timestamp. + * <p> + * e.g. for add paths change in JSON format. + * <pre> + * {@code + * { + * "hasFullImage":1, + * "seqNum":1, + * "pathChanges":[ + * { + * "authzObj":"db1.tbl12", + * "addPaths":[ + * [ + * "db1", + * "tbl12", + * "part121" + * ] + * ], + * "delPaths":[] + * } + * ] + * } + * } + * </pre> + * <p> + * Any changes to this objects require re-running the maven build so DN + * can re-enhance. + */ + +@PersistenceCapable +public class MSentryPathChange implements MSentryChange { + + @PrimaryKey + //This value is auto incremented by JDO + private long changeID; + + // Path change in JSON format. + private String pathChange; + private long createTimeMs; + private String notificationHash; + + public MSentryPathChange(long changeID, String notificationHash, PathsUpdate pathChange) throws TException { + // Each PathsUpdate maps to a MSentryPathChange object. + // The PathsUpdate is generated from a HMS notification log, + // the notification ID is stored as seqNum and + // the notification update is serialized as JSON string. + this.changeID = changeID; + + /* + * notificationHash is a unique identifier for the HMS notification used to prevent + * the same HMS notification message to be processed twice. + * The current HMS code may send different notifications messages with the same ID. To + * keep this ID unique, we calculate the SHA-1 hash of the full message received. + * TODO: This is a temporary fix until HIVE-16886 fixes the issue with duplicated IDs + */ + this.notificationHash = notificationHash; + + this.pathChange = pathChange.JSONSerialize(); + this.createTimeMs = System.currentTimeMillis(); + } + + public long getCreateTimeMs() { + return createTimeMs; + } + + public String getPathChange() { + return pathChange; + } + + public long getChangeID() { + return changeID; + } + + public String getNotificationHash() { + return notificationHash; + } + + @Override + public String toString() { + return "MSentryChange [changeID=" + changeID + " , notificationHash= " + + notificationHash +" , pathChange= " + pathChange + + ", createTime=" + createTimeMs + "]"; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + Long.valueOf(changeID).hashCode(); + result = prime * result + notificationHash.hashCode(); + result = prime * result + ((pathChange == null) ? 0 : pathChange.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; + } + + MSentryPathChange other = (MSentryPathChange) obj; + if (changeID != other.changeID) { + return false; + } + + if (!notificationHash.equals(other.notificationHash)) { + return false; + } + + if (createTimeMs != other.createTimeMs) { + return false; + } + + if (pathChange == null) { + return other.pathChange == null; + } + + return pathChange.equals(other.pathChange); + } +} http://git-wip-us.apache.org/repos/asf/sentry/blob/b97f5c7a/sentry-service/sentry-service-server/src/main/java/org/apache/sentry/provider/db/service/model/MSentryPermChange.java ---------------------------------------------------------------------- diff --git a/sentry-service/sentry-service-server/src/main/java/org/apache/sentry/provider/db/service/model/MSentryPermChange.java b/sentry-service/sentry-service-server/src/main/java/org/apache/sentry/provider/db/service/model/MSentryPermChange.java new file mode 100644 index 0000000..e29e780 --- /dev/null +++ b/sentry-service/sentry-service-server/src/main/java/org/apache/sentry/provider/db/service/model/MSentryPermChange.java @@ -0,0 +1,130 @@ +/** + * 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 org.apache.sentry.hdfs.PermissionsUpdate; +import org.apache.thrift.TException; + +import javax.jdo.annotations.PersistenceCapable; +import javax.jdo.annotations.PrimaryKey; + + +/** + * Database backend store for Sentry permission delta change. Each record + * contains change ID, JSON format of a single Sentry permission change, + * and timestamp. + * <p> + * e.g. for rename privileges change in JSON format. + * <pre> + * {@code + * { + * "hasfullImage":0, + * "seqNum":0, + * "privilegeChanges":{ + * "__RENAME_PRIV__":{ + * "authzObj":"__RENAME_PRIV__", + * "addPrivileges":{ + * "newAuthz":"newAuthz" + * }, + * "delPrivileges":{ + * "oldAuthz":"oldAuthz" + * } + * } + * }, + * "roleChanges":{} + * } + * </pre> + * <p> + * Any changes to this objects require re-running the maven build so DN + * can re-enhance. + */ +@PersistenceCapable +public class MSentryPermChange implements MSentryChange { + + @PrimaryKey + //This value is auto incremented by JDO + private long changeID; + + // Permission change in JSON format. + private String permChange; + private long createTimeMs; + + public MSentryPermChange(long changeID, PermissionsUpdate permChange) throws TException { + this.changeID = changeID; + this.permChange = permChange.JSONSerialize(); + this.createTimeMs = System.currentTimeMillis(); + } + + public long getCreateTimeMs() { + return createTimeMs; + } + + public String getPermChange() { + return permChange; + } + + public long getChangeID() { + return changeID; + } + + @Override + public String toString() { + return "MSentryPermChange [changeID=" + changeID + ", permChange= " + permChange + + ", createTimeMs=" + createTimeMs + "]"; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + Long.valueOf(changeID).hashCode(); + result = prime * result + ((permChange == null) ? 0 : permChange.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; + } + + MSentryPermChange other = (MSentryPermChange) obj; + if (changeID != other.changeID) { + return false; + } + + if (createTimeMs != other.createTimeMs) { + return false; + } + + if (permChange == null) { + return other.permChange == null; + } + + return permChange.equals(other.permChange); + } +}
