http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/bf3eb482/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/generic/service/thrift/SentryGenericPolicyProcessor.java ---------------------------------------------------------------------- diff --git a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/generic/service/thrift/SentryGenericPolicyProcessor.java b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/generic/service/thrift/SentryGenericPolicyProcessor.java new file mode 100644 index 0000000..d6600a0 --- /dev/null +++ b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/generic/service/thrift/SentryGenericPolicyProcessor.java @@ -0,0 +1,549 @@ +/** + * 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.generic.service.thrift; + +import static org.apache.sentry.provider.common.ProviderConstants.AUTHORIZABLE_JOINER; +import static org.apache.sentry.provider.common.ProviderConstants.KV_JOINER; + +import java.lang.reflect.Constructor; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import org.apache.hadoop.conf.Configuration; +import org.apache.sentry.SentryUserException; +import org.apache.sentry.core.common.Authorizable; +import org.apache.sentry.core.model.db.AccessConstants; +import org.apache.sentry.provider.db.SentryAccessDeniedException; +import org.apache.sentry.provider.db.SentryAlreadyExistsException; +import org.apache.sentry.provider.db.SentryInvalidInputException; +import org.apache.sentry.provider.db.SentryNoSuchObjectException; +import org.apache.sentry.provider.db.generic.service.persistent.PrivilegeObject; +import org.apache.sentry.provider.db.generic.service.persistent.SentryStoreLayer; +import org.apache.sentry.provider.db.generic.service.persistent.PrivilegeObject.Builder; +import org.apache.sentry.provider.db.service.persistent.CommitContext; +import org.apache.sentry.provider.db.service.thrift.PolicyStoreConstants; +import org.apache.sentry.provider.db.service.thrift.SentryConfigurationException; +import org.apache.sentry.provider.db.service.thrift.SentryPolicyStoreProcessor; +import org.apache.sentry.service.thrift.ServiceConstants.ServerConfig; +import org.apache.sentry.service.thrift.Status; +import org.apache.sentry.service.thrift.TSentryResponseStatus; +import org.apache.thrift.TException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.annotations.VisibleForTesting; +import com.google.common.base.Splitter; +import com.google.common.base.Strings; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Lists; +import com.google.common.collect.Sets; + +public class SentryGenericPolicyProcessor implements SentryGenericPolicyService.Iface { + private static final Logger LOGGER = LoggerFactory.getLogger(SentryGenericPolicyProcessor.class); + private final Configuration conf; + private final ImmutableSet<String> adminGroups; + private final SentryStoreLayer store; + private final NotificationHandlerInvoker handerInvoker; + + public static final String SENTRY_GENERIC_SERVICE_NAME = "SentryGenericPolicyService"; + + public SentryGenericPolicyProcessor(Configuration conf) throws Exception { + this.store = createStore(conf); + this.handerInvoker = new NotificationHandlerInvoker(createHandlers(conf)); + this.conf = conf; + adminGroups = ImmutableSet.copyOf(toTrimedLower(Sets.newHashSet(conf.getStrings( + ServerConfig.ADMIN_GROUPS, new String[]{})))); + } + + @VisibleForTesting + public SentryGenericPolicyProcessor(Configuration conf, SentryStoreLayer store) throws Exception { + this.store = store; + this.handerInvoker = new NotificationHandlerInvoker(createHandlers(conf)); + this.conf = conf; + adminGroups = ImmutableSet.copyOf(toTrimedLower(Sets.newHashSet(conf.getStrings( + ServerConfig.ADMIN_GROUPS, new String[]{})))); + } + + private void authorize(String requestorUser, Set<String> requestorGroups) + throws SentryAccessDeniedException { + if (!inAdminGroups(requestorGroups)) { + String msg = "User: " + requestorUser + " is part of " + requestorGroups + + " which does not, intersect admin groups " + adminGroups; + LOGGER.warn(msg); + throw new SentryAccessDeniedException("Access denied to " + requestorUser); + } + } + + private Set<String> toTrimedLower(Set<String> s) { + if (null == s) return new HashSet<String>(); + Set<String> result = Sets.newHashSet(); + for (String v : s) { + result.add(v.trim().toLowerCase()); + } + return result; + } + + private String toTrimedLower(String s) { + if (Strings.isNullOrEmpty(s)){ + return ""; + } + return s.trim().toLowerCase(); + } + + public static Set<String> getRequestorGroups(Configuration conf, String userName) throws SentryUserException { + return SentryPolicyStoreProcessor.getGroupsFromUserName(conf, userName); + } + + private boolean inAdminGroups(Set<String> requestorGroups) { + requestorGroups = toTrimedLower(requestorGroups); + if (Sets.intersection(adminGroups, requestorGroups).isEmpty()) { + return false; + } else return true; + } + + public static SentryStoreLayer createStore(Configuration conf) throws SentryConfigurationException { + SentryStoreLayer storeLayer = null; + String Store = conf.get(PolicyStoreConstants.SENTRY_GENERIC_POLICY_STORE, + PolicyStoreConstants.SENTRY_GENERIC_POLICY_STORE_DEFAULT); + + if (Strings.isNullOrEmpty(Store)) { + throw new SentryConfigurationException("the parameter configuration for sentry.generic.policy.store can't be empty"); + } + try { + storeLayer = createInstance(Store, conf, SentryStoreLayer.class); + } catch (Exception e) { + throw new SentryConfigurationException("Create sentryStore error: " + e.getMessage(), e); + } + return storeLayer; + } + + public static List<NotificationHandler> createHandlers(Configuration conf) throws SentryConfigurationException { + + List<NotificationHandler> handlers = Lists.newArrayList(); + Iterable<String> notificationHandlers = Splitter.onPattern("[\\s,]").trimResults() + .omitEmptyStrings().split(conf.get(PolicyStoreConstants.SENTRY_GENERIC_POLICY_NOTIFICATION, "")); + try { + for (String notificationHandler : notificationHandlers) { + handlers.add(createInstance(notificationHandler, conf, NotificationHandler.class)); + } + } catch (Exception e) { + throw new SentryConfigurationException("Create notificationHandlers error: " + e.getMessage(), e); + } + return handlers; + } + + @SuppressWarnings("unchecked") + public static <T> T createInstance(String className, Configuration conf, Class<T> iface) throws Exception { + T result; + try { + Class clazz = Class.forName(className); + if (!iface.isAssignableFrom(clazz)) { + throw new IllegalArgumentException("Class " + clazz + " is not a " + + iface.getName()); + } + Constructor<T> meth = (Constructor<T>)clazz.getDeclaredConstructor(Configuration.class); + meth.setAccessible(true); + result = meth.newInstance(new Object[]{conf}); + } catch (Exception e) { + throw new RuntimeException(e); + } + return result; + } + + private <T> Response<T> requestHandle(RequestHandler<T> handler) { + Response<T> response = new Response<T>(); + try { + response = handler.handle(); + } catch (SentryAccessDeniedException e) { + LOGGER.error(e.getMessage(), e); + response.status = Status.AccessDenied(e.getMessage(), e); + } catch (SentryAlreadyExistsException e) { + LOGGER.error(e.getMessage(), e); + response.status = Status.AlreadyExists(e.getMessage(), e); + } catch (SentryNoSuchObjectException e) { + LOGGER.error(e.getMessage(), e); + response.status = Status.NoSuchObject(e.getMessage(), e); + } catch (SentryInvalidInputException e) { + String msg = "Invalid input privilege object"; + LOGGER.error(msg, e); + response.status = Status.InvalidInput(msg, e); + } catch (Exception e) { + String msg = "Unknown error:" + e.getMessage(); + LOGGER.error(msg, e); + response.status = Status.RuntimeError(msg, e); + } + return response; + } + + private PrivilegeObject toPrivilegeObject(TSentryPrivilege tSentryPrivilege) { + Boolean grantOption; + if (tSentryPrivilege.getGrantOption().equals(TSentryGrantOption.TRUE)) { + grantOption = true; + } else if (tSentryPrivilege.getGrantOption().equals(TSentryGrantOption.FALSE)) { + grantOption = false; + } else { + grantOption = null; + } + return new Builder().setComponent(tSentryPrivilege.getComponent()) + .setService(tSentryPrivilege.getServiceName()) + .setAuthorizables(toAuthorizables(tSentryPrivilege.getAuthorizables())) + .setAction(tSentryPrivilege.getAction()) + .withGrantOption(grantOption) + .build(); + } + + private TSentryPrivilege fromPrivilegeObject(PrivilegeObject privilege) { + + TSentryPrivilege tPrivilege = new TSentryPrivilege(privilege.getComponent(), privilege.getService(), + fromAuthorizable(privilege.getAuthorizables()), + privilege.getAction()); + if (privilege.getGrantOption() == null) { + tPrivilege.setGrantOption(TSentryGrantOption.UNSET); + } else if (privilege.getGrantOption()) { + tPrivilege.setGrantOption(TSentryGrantOption.TRUE); + } else { + tPrivilege.setGrantOption(TSentryGrantOption.FALSE); + } + return tPrivilege; + } + + private List<TAuthorizable> fromAuthorizable(List<? extends Authorizable> authorizables) { + List<TAuthorizable> tAuthorizables = Lists.newArrayList(); + for (Authorizable authorizable : authorizables) { + tAuthorizables.add(new TAuthorizable(authorizable.getTypeName(), authorizable.getName())); + } + return tAuthorizables; + } + + private List<? extends Authorizable> toAuthorizables(List<TAuthorizable> tAuthorizables) { + List<Authorizable> authorizables = Lists.newArrayList(); + if (tAuthorizables == null) { + return authorizables; + } + for (final TAuthorizable tAuthorizable : tAuthorizables) { + authorizables.add(new Authorizable() { + @Override + public String getTypeName() { + return tAuthorizable.getType(); + } + @Override + public String getName() { + return tAuthorizable.getName(); + } + }); + } + return authorizables; + } + + private Set<String> buildPermissions(Set<PrivilegeObject> privileges) { + Set<String> permissions = Sets.newHashSet(); + for (PrivilegeObject privilege : privileges) { + List<String> hierarchy = Lists.newArrayList(); + for (Authorizable authorizable : privilege.getAuthorizables()) { + hierarchy.add(KV_JOINER.join(authorizable.getTypeName(),authorizable.getName())); + } + hierarchy.add(KV_JOINER.join("action", privilege.getAction())); + permissions.add(AUTHORIZABLE_JOINER.join(hierarchy)); + } + return permissions; + } + + @Override + public TCreateSentryRoleResponse create_sentry_role( + final TCreateSentryRoleRequest request) throws TException { + Response<Void> respose = requestHandle(new RequestHandler<Void>() { + @Override + public Response<Void> handle() throws Exception { + authorize(request.getRequestorUserName(), + getRequestorGroups(conf, request.getRequestorUserName())); + CommitContext context = store.createRole(request.getComponent(), request.getRoleName(), request.getRequestorUserName()); + return new Response<Void>(Status.OK(), context); + } + }); + + TCreateSentryRoleResponse tResponse = new TCreateSentryRoleResponse(respose.status); + if (Status.OK.getCode() == respose.status.getValue()) { + handerInvoker.create_sentry_role(respose.context, request, tResponse); + } + return tResponse; + } + + @Override + public TDropSentryRoleResponse drop_sentry_role(final TDropSentryRoleRequest request) + throws TException { + Response<Void> respose = requestHandle(new RequestHandler<Void>() { + @Override + public Response<Void> handle() throws Exception { + authorize(request.getRequestorUserName(), + getRequestorGroups(conf, request.getRequestorUserName())); + CommitContext context = store.dropRole(request.getComponent(), request.getRoleName(), request.getRequestorUserName()); + return new Response<Void>(Status.OK(), context); + } + }); + + TDropSentryRoleResponse tResponse = new TDropSentryRoleResponse(respose.status); + if (Status.OK.getCode() == respose.status.getValue()) { + handerInvoker.drop_sentry_role(respose.context, request, tResponse); + } + return tResponse; + } + + @Override + public TAlterSentryRoleGrantPrivilegeResponse alter_sentry_role_grant_privilege( + final TAlterSentryRoleGrantPrivilegeRequest request) throws TException { + Response<Void> respose = requestHandle(new RequestHandler<Void>() { + @Override + public Response<Void> handle() throws Exception { + CommitContext context = store.alterRoleGrantPrivilege(request.getComponent(), request.getRoleName(), + toPrivilegeObject(request.getPrivilege()), + request.getRequestorUserName()); + return new Response<Void>(Status.OK(), context); + } + }); + + TAlterSentryRoleGrantPrivilegeResponse tResponse = new TAlterSentryRoleGrantPrivilegeResponse(respose.status); + if (Status.OK.getCode() == respose.status.getValue()) { + handerInvoker.alter_sentry_role_grant_privilege(respose.context, request, tResponse); + } + return tResponse; + } + + @Override + public TAlterSentryRoleRevokePrivilegeResponse alter_sentry_role_revoke_privilege( + final TAlterSentryRoleRevokePrivilegeRequest request) throws TException { + Response<Void> respose = requestHandle(new RequestHandler<Void>() { + @Override + public Response<Void> handle() throws Exception { + CommitContext context = store.alterRoleRevokePrivilege(request.getComponent(), request.getRoleName(), + toPrivilegeObject(request.getPrivilege()), + request.getRequestorUserName()); + return new Response<Void>(Status.OK(), context); + } + }); + + TAlterSentryRoleRevokePrivilegeResponse tResponse = new TAlterSentryRoleRevokePrivilegeResponse(respose.status); + if (Status.OK.getCode() == respose.status.getValue()) { + handerInvoker.alter_sentry_role_revoke_privilege(respose.context, request, tResponse); + } + return tResponse; + } + + @Override + public TAlterSentryRoleAddGroupsResponse alter_sentry_role_add_groups( + final TAlterSentryRoleAddGroupsRequest request) throws TException { + Response<Void> respose = requestHandle(new RequestHandler<Void>() { + @Override + public Response<Void> handle() throws Exception { + authorize(request.getRequestorUserName(), + getRequestorGroups(conf, request.getRequestorUserName())); + CommitContext context = store.alterRoleAddGroups( + request.getComponent(), request.getRoleName(), request.getGroups(), + request.getRequestorUserName()); + return new Response<Void>(Status.OK(), context); + } + }); + + TAlterSentryRoleAddGroupsResponse tResponse = new TAlterSentryRoleAddGroupsResponse(respose.status); + if (Status.OK.getCode() == respose.status.getValue()) { + handerInvoker.alter_sentry_role_add_groups(respose.context, request, tResponse); + } + return tResponse; + } + + @Override + public TAlterSentryRoleDeleteGroupsResponse alter_sentry_role_delete_groups( + final TAlterSentryRoleDeleteGroupsRequest request) throws TException { + Response<Void> respose = requestHandle(new RequestHandler<Void>() { + @Override + public Response<Void> handle() throws Exception { + authorize(request.getRequestorUserName(), + getRequestorGroups(conf, request.getRequestorUserName())); + CommitContext context = store.alterRoleDeleteGroups( + request.getComponent(), request.getRoleName(), request.getGroups(), + request.getRequestorUserName()); + return new Response<Void>(Status.OK(), context); + } + }); + + TAlterSentryRoleDeleteGroupsResponse tResponse = new TAlterSentryRoleDeleteGroupsResponse(respose.status); + if (Status.OK.getCode() == respose.status.getValue()) { + handerInvoker.alter_sentry_role_delete_groups(respose.context, request, tResponse); + } + return tResponse; + } + + @Override + public TListSentryRolesResponse list_sentry_roles_by_group( + final TListSentryRolesRequest request) throws TException { + Response<Set<TSentryRole>> respose = requestHandle(new RequestHandler<Set<TSentryRole>>() { + @Override + public Response<Set<TSentryRole>> handle() throws Exception { + Set<String> groups = getRequestorGroups(conf, request.getRequestorUserName()); + if (AccessConstants.ALL.equalsIgnoreCase(request.getGroupName())) { + //check all groups which requestorUserName belongs to + } else { + boolean admin = inAdminGroups(groups); + //Only admin users can list all roles in the system ( groupname = null) + //Non admin users are only allowed to list only groups which they belong to + if(!admin && (request.getGroupName() == null || !groups.contains(request.getGroupName()))) { + throw new SentryAccessDeniedException("Access denied to " + request.getRequestorUserName()); + } + groups.clear(); + groups.add(request.getGroupName()); + } + + Set<String> roleNames = store.getRolesByGroups(request.getComponent(), groups); + Set<TSentryRole> tSentryRoles = Sets.newHashSet(); + for (String roleName : roleNames) { + Set<String> groupsForRoleName = store.getGroupsByRoles(request.getComponent(), Sets.newHashSet(roleName)); + tSentryRoles.add(new TSentryRole(roleName, groupsForRoleName)); + } + return new Response<Set<TSentryRole>>(Status.OK(), tSentryRoles); + } + }); + TListSentryRolesResponse tResponse = new TListSentryRolesResponse(); + tResponse.setStatus(respose.status); + tResponse.setRoles(respose.content); + return tResponse; + } + + @Override + public TListSentryPrivilegesResponse list_sentry_privileges_by_role( + final TListSentryPrivilegesRequest request) throws TException { + Response<Set<TSentryPrivilege>> respose = requestHandle(new RequestHandler<Set<TSentryPrivilege>>() { + @Override + public Response<Set<TSentryPrivilege>> handle() throws Exception { + Set<String> groups = getRequestorGroups(conf, request.getRequestorUserName()); + if (!inAdminGroups(groups)) { + Set<String> roleNamesForGroups = toTrimedLower(store.getRolesByGroups(request.getComponent(), groups)); + if (!roleNamesForGroups.contains(toTrimedLower(request.getRoleName()))) { + throw new SentryAccessDeniedException("Access denied to " + request.getRequestorUserName()); + } + } + Set<PrivilegeObject> privileges = store.getPrivilegesByProvider(request.getComponent(), + request.getServiceName(), + Sets.newHashSet(request.getRoleName()), + null, + toAuthorizables(request.getAuthorizables())); + Set<TSentryPrivilege> tSentryPrivileges = Sets.newHashSet(); + for (PrivilegeObject privilege : privileges) { + tSentryPrivileges.add(fromPrivilegeObject(privilege)); + } + return new Response<Set<TSentryPrivilege>>(Status.OK(), tSentryPrivileges); + } + }); + TListSentryPrivilegesResponse tResponse = new TListSentryPrivilegesResponse(); + tResponse.setStatus(respose.status); + tResponse.setPrivileges(respose.content); + return tResponse; + } + + @Override + public TListSentryPrivilegesForProviderResponse list_sentry_privileges_for_provider( + final TListSentryPrivilegesForProviderRequest request) throws TException { + Response<Set<String>> respose = requestHandle(new RequestHandler<Set<String>>() { + @Override + public Response<Set<String>> handle() throws Exception { + Set<String> activeRoleNames = toTrimedLower(request.getRoleSet().getRoles()); + Set<String> roleNamesForGroups = store.getRolesByGroups(request.getComponent(), request.getGroups()); + Set<String> rolesToQuery = request.getRoleSet().isAll() ? roleNamesForGroups : Sets.intersection(activeRoleNames, roleNamesForGroups); + Set<PrivilegeObject> privileges = store.getPrivilegesByProvider(request.getComponent(), + request.getServiceName(), + rolesToQuery, null, + toAuthorizables(request.getAuthorizables())); + return new Response<Set<String>>(Status.OK(), buildPermissions(privileges)); + } + }); + TListSentryPrivilegesForProviderResponse tResponse = new TListSentryPrivilegesForProviderResponse(); + tResponse.setStatus(respose.status); + tResponse.setPrivileges(respose.content); + return tResponse; + } + + @Override + public TDropPrivilegesResponse drop_sentry_privilege( + final TDropPrivilegesRequest request) throws TException { + Response<Void> respose = requestHandle(new RequestHandler<Void>() { + @Override + public Response<Void> handle() throws Exception { + authorize(request.getRequestorUserName(), + getRequestorGroups(conf, request.getRequestorUserName())); + CommitContext context = store.dropPrivilege(request.getComponent(), + toPrivilegeObject(request.getPrivilege()), + request.getRequestorUserName()); + return new Response<Void>(Status.OK(), context); + } + }); + + TDropPrivilegesResponse tResponse = new TDropPrivilegesResponse(respose.status); + if (Status.OK.getCode() == respose.status.getValue()) { + handerInvoker.drop_sentry_privilege(respose.context, request, tResponse); + } + return tResponse; + } + + @Override + public TRenamePrivilegesResponse rename_sentry_privilege( + final TRenamePrivilegesRequest request) throws TException { + Response<Void> respose = requestHandle(new RequestHandler<Void>() { + @Override + public Response<Void> handle() throws Exception { + authorize(request.getRequestorUserName(), + getRequestorGroups(conf, request.getRequestorUserName())); + CommitContext context = store.renamePrivilege(request.getComponent(), request.getServiceName(), + toAuthorizables(request.getOldAuthorizables()), + toAuthorizables(request.getNewAuthorizables()), + request.getRequestorUserName()); + return new Response<Void>(Status.OK(),context); + } + }); + + TRenamePrivilegesResponse tResponse = new TRenamePrivilegesResponse(respose.status); + if (Status.OK.getCode() == respose.status.getValue()) { + handerInvoker.rename_sentry_privilege(respose.context, request, tResponse); + } + return tResponse; + } + + private static class Response<T> { + TSentryResponseStatus status; + CommitContext context; + T content; + + Response() { + } + + Response(TSentryResponseStatus status, CommitContext context) { + this(status,context,null); + } + + Response(TSentryResponseStatus status, T content) { + this(status,null,content); + } + + Response(TSentryResponseStatus status, CommitContext context, T content) { + this.status = status; + this.context = context; + this.content = content; + } + } + private interface RequestHandler <T>{ + public Response<T> handle() throws Exception ; + } +} \ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/bf3eb482/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/generic/service/thrift/SentryGenericPolicyProcessorFactory.java ---------------------------------------------------------------------- diff --git a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/generic/service/thrift/SentryGenericPolicyProcessorFactory.java b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/generic/service/thrift/SentryGenericPolicyProcessorFactory.java new file mode 100644 index 0000000..71ce579 --- /dev/null +++ b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/generic/service/thrift/SentryGenericPolicyProcessorFactory.java @@ -0,0 +1,41 @@ +/** + * 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.generic.service.thrift; + +import org.apache.hadoop.conf.Configuration; +import org.apache.sentry.provider.db.generic.service.thrift.SentryGenericPolicyService; +import org.apache.sentry.provider.db.service.thrift.PolicyStoreConstants.PolicyStoreServerConfig; +import org.apache.sentry.service.thrift.ProcessorFactory; +import org.apache.thrift.TMultiplexedProcessor; +import org.apache.thrift.TProcessor; + +public class SentryGenericPolicyProcessorFactory extends ProcessorFactory { + + public SentryGenericPolicyProcessorFactory(Configuration conf) { + super(conf); + } + + @Override + public boolean register(TMultiplexedProcessor multiplexedProcessor) throws Exception { + SentryGenericPolicyProcessor processHandler = new SentryGenericPolicyProcessor(conf); + TProcessor processor = new SentryGenericPolicyService.Processor<SentryGenericPolicyService.Iface>(processHandler); + multiplexedProcessor.registerProcessor(SentryGenericPolicyProcessor.SENTRY_GENERIC_SERVICE_NAME, processor); + return true; + } + +} http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/bf3eb482/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/generic/service/thrift/SentryGenericServiceClient.java ---------------------------------------------------------------------- diff --git a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/generic/service/thrift/SentryGenericServiceClient.java b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/generic/service/thrift/SentryGenericServiceClient.java new file mode 100644 index 0000000..9f4a292 --- /dev/null +++ b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/generic/service/thrift/SentryGenericServiceClient.java @@ -0,0 +1,536 @@ +/** + * 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.generic.service.thrift; + +import java.io.IOException; +import java.net.InetSocketAddress; +import java.security.PrivilegedExceptionAction; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import javax.security.auth.callback.CallbackHandler; + +import org.apache.hadoop.conf.Configuration; +import org.apache.hadoop.net.NetUtils; +import org.apache.hadoop.security.SaslRpcServer; +import org.apache.hadoop.security.SaslRpcServer.AuthMethod; +import org.apache.hadoop.security.SecurityUtil; +import org.apache.hadoop.security.UserGroupInformation; +import org.apache.sentry.SentryUserException; +import org.apache.sentry.core.common.ActiveRoleSet; +import org.apache.sentry.core.common.Authorizable; +import org.apache.sentry.core.model.db.AccessConstants; +import org.apache.sentry.service.thrift.ServiceConstants.ClientConfig; +import org.apache.sentry.service.thrift.ServiceConstants.ServerConfig; +import org.apache.sentry.service.thrift.Status; +import org.apache.sentry.service.thrift.sentry_common_serviceConstants; +import org.apache.thrift.TException; +import org.apache.thrift.protocol.TBinaryProtocol; +import org.apache.thrift.protocol.TMultiplexedProtocol; +import org.apache.thrift.transport.TSaslClientTransport; +import org.apache.thrift.transport.TSocket; +import org.apache.thrift.transport.TTransport; +import org.apache.thrift.transport.TTransportException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.base.Preconditions; +import com.google.common.collect.Lists; + +public class SentryGenericServiceClient { + private final Configuration conf; + private final InetSocketAddress serverAddress; + private final boolean kerberos; + private final String[] serverPrincipalParts; + private SentryGenericPolicyService.Client client; + private TTransport transport; + private int connectionTimeout; + private static final Logger LOGGER = LoggerFactory + .getLogger(SentryGenericServiceClient.class); + private static final String THRIFT_EXCEPTION_MESSAGE = "Thrift exception occured "; + + /** + * This transport wraps the Sasl transports to set up the right UGI context for open(). + */ + public static class UgiSaslClientTransport extends TSaslClientTransport { + protected UserGroupInformation ugi = null; + + public UgiSaslClientTransport(String mechanism, String authorizationId, + String protocol, String serverName, Map<String, String> props, + CallbackHandler cbh, TTransport transport, boolean wrapUgi) + throws IOException { + super(mechanism, authorizationId, protocol, serverName, props, cbh, + transport); + if (wrapUgi) { + ugi = UserGroupInformation.getLoginUser(); + } + } + + // open the SASL transport with using the current UserGroupInformation + // This is needed to get the current login context stored + @Override + public void open() throws TTransportException { + if (ugi == null) { + baseOpen(); + } else { + try { + if (ugi.isFromKeytab()) { + ugi.checkTGTAndReloginFromKeytab(); + } + ugi.doAs(new PrivilegedExceptionAction<Void>() { + public Void run() throws TTransportException { + baseOpen(); + return null; + } + }); + } catch (IOException e) { + throw new TTransportException("Failed to open SASL transport", e); + } catch (InterruptedException e) { + throw new TTransportException( + "Interrupted while opening underlying transport", e); + } + } + } + + private void baseOpen() throws TTransportException { + super.open(); + } + } + + public SentryGenericServiceClient(Configuration conf) throws IOException { + this.conf = conf; + Preconditions.checkNotNull(this.conf, "Configuration object cannot be null"); + this.serverAddress = NetUtils.createSocketAddr(Preconditions.checkNotNull( + conf.get(ClientConfig.SERVER_RPC_ADDRESS), "Config key " + + ClientConfig.SERVER_RPC_ADDRESS + " is required"), conf.getInt( + ClientConfig.SERVER_RPC_PORT, ClientConfig.SERVER_RPC_PORT_DEFAULT)); + this.connectionTimeout = conf.getInt(ClientConfig.SERVER_RPC_CONN_TIMEOUT, + ClientConfig.SERVER_RPC_CONN_TIMEOUT_DEFAULT); + kerberos = ServerConfig.SECURITY_MODE_KERBEROS.equalsIgnoreCase( + conf.get(ServerConfig.SECURITY_MODE, ServerConfig.SECURITY_MODE_KERBEROS).trim()); + transport = new TSocket(serverAddress.getHostName(), + serverAddress.getPort(), connectionTimeout); + if (kerberos) { + String serverPrincipal = Preconditions.checkNotNull(conf.get(ServerConfig.PRINCIPAL), ServerConfig.PRINCIPAL + " is required"); + + // Resolve server host in the same way as we are doing on server side + serverPrincipal = SecurityUtil.getServerPrincipal(serverPrincipal, serverAddress.getAddress()); + LOGGER.debug("Using server kerberos principal: " + serverPrincipal); + + serverPrincipalParts = SaslRpcServer.splitKerberosName(serverPrincipal); + Preconditions.checkArgument(serverPrincipalParts.length == 3, + "Kerberos principal should have 3 parts: " + serverPrincipal); + boolean wrapUgi = "true".equalsIgnoreCase(conf + .get(ServerConfig.SECURITY_USE_UGI_TRANSPORT, "true")); + transport = new UgiSaslClientTransport(AuthMethod.KERBEROS.getMechanismName(), + null, serverPrincipalParts[0], serverPrincipalParts[1], + ClientConfig.SASL_PROPERTIES, null, transport, wrapUgi); + } else { + serverPrincipalParts = null; + } + try { + transport.open(); + } catch (TTransportException e) { + throw new IOException("Transport exception while opening transport: " + e.getMessage(), e); + } + LOGGER.debug("Successfully opened transport: " + transport + " to " + serverAddress); + TMultiplexedProtocol protocol = new TMultiplexedProtocol( + new TBinaryProtocol(transport), + SentryGenericPolicyProcessor.SENTRY_GENERIC_SERVICE_NAME); + client = new SentryGenericPolicyService.Client(protocol); + LOGGER.debug("Successfully created client"); + } + + + + /** + * Create a sentry role + * @param requestorUserName: user on whose behalf the request is issued + * @param roleName: Name of the role + * @param component: The request is issued to which component + * @throws SentryUserException + */ + public synchronized void createRole(String requestorUserName, String roleName, String component) + throws SentryUserException { + TCreateSentryRoleRequest request = new TCreateSentryRoleRequest(); + request.setProtocol_version(sentry_common_serviceConstants.TSENTRY_SERVICE_V2); + request.setRequestorUserName(requestorUserName); + request.setRoleName(roleName); + request.setComponent(component); + try { + TCreateSentryRoleResponse response = client.create_sentry_role(request); + Status.throwIfNotOk(response.getStatus()); + } catch (TException e) { + throw new SentryUserException(THRIFT_EXCEPTION_MESSAGE, e); + } + } + + public void createRoleIfNotExist(String requestorUserName, String roleName, String component) throws SentryUserException { + TCreateSentryRoleRequest request = new TCreateSentryRoleRequest(); + request.setProtocol_version(sentry_common_serviceConstants.TSENTRY_SERVICE_V2); + request.setRequestorUserName(requestorUserName); + request.setRoleName(roleName); + request.setComponent(component); + try { + TCreateSentryRoleResponse response = client.create_sentry_role(request); + Status status = Status.fromCode(response.getStatus().getValue()); + if (status == Status.ALREADY_EXISTS) { + return; + } + Status.throwIfNotOk(response.getStatus()); + } catch (TException e) { + throw new SentryUserException(THRIFT_EXCEPTION_MESSAGE, e); + } + } + + /** + * Drop a sentry role + * @param requestorUserName: user on whose behalf the request is issued + * @param roleName: Name of the role + * @param component: The request is issued to which component + * @throws SentryUserException + */ + public void dropRole(String requestorUserName, + String roleName, String component) + throws SentryUserException { + dropRole(requestorUserName, roleName, component, false); + } + + public void dropRoleIfExists(String requestorUserName, + String roleName, String component) + throws SentryUserException { + dropRole(requestorUserName, roleName, component, true); + } + + private void dropRole(String requestorUserName, + String roleName, String component , boolean ifExists) + throws SentryUserException { + TDropSentryRoleRequest request = new TDropSentryRoleRequest(); + request.setProtocol_version(sentry_common_serviceConstants.TSENTRY_SERVICE_V2); + request.setRequestorUserName(requestorUserName); + request.setRoleName(roleName); + request.setComponent(component); + try { + TDropSentryRoleResponse response = client.drop_sentry_role(request); + Status status = Status.fromCode(response.getStatus().getValue()); + if (ifExists && status == Status.NO_SUCH_OBJECT) { + return; + } + Status.throwIfNotOk(response.getStatus()); + } catch (TException e) { + throw new SentryUserException(THRIFT_EXCEPTION_MESSAGE, e); + } + } + + /** + * add a sentry role to groups. + * @param requestorUserName: user on whose behalf the request is issued + * @param roleName: Name of the role + * @param component: The request is issued to which component + * @param groups: The name of groups + * @throws SentryUserException + */ + public void addRoleToGroups(String requestorUserName, String roleName, + String component, Set<String> groups) throws SentryUserException { + TAlterSentryRoleAddGroupsRequest request = new TAlterSentryRoleAddGroupsRequest(); + request.setProtocol_version(sentry_common_serviceConstants.TSENTRY_SERVICE_V2); + request.setRequestorUserName(requestorUserName); + request.setRoleName(roleName); + request.setGroups(groups); + request.setComponent(component); + + try { + TAlterSentryRoleAddGroupsResponse response = client.alter_sentry_role_add_groups(request); + Status.throwIfNotOk(response.getStatus()); + } catch (TException e) { + throw new SentryUserException(THRIFT_EXCEPTION_MESSAGE, e); + } + } + + /** + * delete a sentry role from groups. + * @param requestorUserName: user on whose behalf the request is issued + * @param roleName: Name of the role + * @param component: The request is issued to which component + * @param groups: The name of groups + * @throws SentryUserException + */ + public void deleteRoleToGroups(String requestorUserName, String roleName, + String component, Set<String> groups) throws SentryUserException { + TAlterSentryRoleDeleteGroupsRequest request = new TAlterSentryRoleDeleteGroupsRequest(); + request.setProtocol_version(sentry_common_serviceConstants.TSENTRY_SERVICE_V2); + request.setRequestorUserName(requestorUserName); + request.setRoleName(roleName); + request.setGroups(groups); + request.setComponent(component); + + try { + TAlterSentryRoleDeleteGroupsResponse response = client.alter_sentry_role_delete_groups(request); + Status.throwIfNotOk(response.getStatus()); + } catch (TException e) { + throw new SentryUserException(THRIFT_EXCEPTION_MESSAGE, e); + } + } + + /** + * grant privilege + * @param requestorUserName: user on whose behalf the request is issued + * @param roleName: Name of the role + * @param component: The request is issued to which component + * @param privilege + * @throws SentryUserException + */ + public void grantPrivilege(String requestorUserName, String roleName, + String component, TSentryPrivilege privilege) throws SentryUserException { + TAlterSentryRoleGrantPrivilegeRequest request = new TAlterSentryRoleGrantPrivilegeRequest(); + request.setProtocol_version(sentry_common_serviceConstants.TSENTRY_SERVICE_V2); + request.setComponent(component); + request.setRoleName(roleName); + request.setRequestorUserName(requestorUserName); + request.setPrivilege(privilege); + + try { + TAlterSentryRoleGrantPrivilegeResponse response = client.alter_sentry_role_grant_privilege(request); + Status.throwIfNotOk(response.getStatus()); + } catch (TException e) { + throw new SentryUserException(THRIFT_EXCEPTION_MESSAGE, e); + } + } + + /** + * revoke privilege + * @param requestorUserName: user on whose behalf the request is issued + * @param roleName: Name of the role + * @param component: The request is issued to which component + * @param privilege + * @throws SentryUserException + */ + public void revokePrivilege(String requestorUserName, String roleName, + String component, TSentryPrivilege privilege) throws SentryUserException { + TAlterSentryRoleRevokePrivilegeRequest request = new TAlterSentryRoleRevokePrivilegeRequest(); + request.setProtocol_version(sentry_common_serviceConstants.TSENTRY_SERVICE_V2); + request.setComponent(component); + request.setRequestorUserName(requestorUserName); + request.setRoleName(roleName); + request.setPrivilege(privilege); + + try { + TAlterSentryRoleRevokePrivilegeResponse response = client.alter_sentry_role_revoke_privilege(request); + Status.throwIfNotOk(response.getStatus()); + } catch (TException e) { + throw new SentryUserException(THRIFT_EXCEPTION_MESSAGE, e); + } + } + + /** + * drop privilege + * @param requestorUserName: user on whose behalf the request is issued + * @param roleName: Name of the role + * @param component: The request is issued to which component + * @param privilege + * @throws SentryUserException + */ + public void dropPrivilege(String requestorUserName,String component, + TSentryPrivilege privilege) throws SentryUserException { + TDropPrivilegesRequest request = new TDropPrivilegesRequest(); + request.setProtocol_version(sentry_common_serviceConstants.TSENTRY_SERVICE_V2); + request.setComponent(component); + request.setRequestorUserName(requestorUserName); + request.setPrivilege(privilege); + + try { + TDropPrivilegesResponse response = client.drop_sentry_privilege(request); + Status.throwIfNotOk(response.getStatus()); + } catch (TException e) { + throw new SentryUserException(THRIFT_EXCEPTION_MESSAGE, e); + } + } + + /** + * rename privilege + * @param requestorUserName: user on whose behalf the request is issued + * @param component: The request is issued to which component + * @param serviceName: The Authorizable belongs to which service + * @param oldAuthorizables + * @param newAuthorizables + * @throws SentryUserException + */ + public void renamePrivilege(String requestorUserName, String component, + String serviceName, List<? extends Authorizable> oldAuthorizables, + List<? extends Authorizable> newAuthorizables) throws SentryUserException { + if ((oldAuthorizables == null) || (oldAuthorizables.size() == 0) + || (newAuthorizables == null) || (newAuthorizables.size() == 0)) { + throw new SentryUserException("oldAuthorizables and newAuthorizables can't be null or empty"); + } + + TRenamePrivilegesRequest request = new TRenamePrivilegesRequest(); + request.setProtocol_version(sentry_common_serviceConstants.TSENTRY_SERVICE_V2); + request.setComponent(component); + request.setRequestorUserName(requestorUserName); + request.setServiceName(serviceName); + + List<TAuthorizable> oldTAuthorizables = Lists.newArrayList(); + List<TAuthorizable> newTAuthorizables = Lists.newArrayList(); + for (Authorizable authorizable : oldAuthorizables) { + oldTAuthorizables.add(new TAuthorizable(authorizable.getTypeName(), authorizable.getName())); + request.setOldAuthorizables(oldTAuthorizables); + } + for (Authorizable authorizable : newAuthorizables) { + newTAuthorizables.add(new TAuthorizable(authorizable.getTypeName(), authorizable.getName())); + request.setNewAuthorizables(newTAuthorizables); + } + + try { + TRenamePrivilegesResponse response = client.rename_sentry_privilege(request); + Status.throwIfNotOk(response.getStatus()); + } catch (TException e) { + throw new SentryUserException(THRIFT_EXCEPTION_MESSAGE, e); + } + } + + /** + * Gets sentry role objects for a given groupName using the Sentry service + * @param requestorUserName : user on whose behalf the request is issued + * @param groupName : groupName to look up ( if null returns all roles for groups related to requestorUserName) + * @param component: The request is issued to which component + * @return Set of thrift sentry role objects + * @throws SentryUserException + */ + public synchronized Set<TSentryRole> listRolesByGroupName( + String requestorUserName, + String groupName, + String component) + throws SentryUserException { + TListSentryRolesRequest request = new TListSentryRolesRequest(); + request.setProtocol_version(sentry_common_serviceConstants.TSENTRY_SERVICE_V2); + request.setRequestorUserName(requestorUserName); + request.setGroupName(groupName); + request.setComponent(component); + TListSentryRolesResponse response; + try { + response = client.list_sentry_roles_by_group(request); + Status.throwIfNotOk(response.getStatus()); + return response.getRoles(); + } catch (TException e) { + throw new SentryUserException(THRIFT_EXCEPTION_MESSAGE, e); + } + } + + public Set<TSentryRole> listUserRoles(String requestorUserName, String component) + throws SentryUserException { + return listRolesByGroupName(requestorUserName, AccessConstants.ALL, component); + } + + public Set<TSentryRole> listAllRoles(String requestorUserName, String component) + throws SentryUserException { + return listRolesByGroupName(requestorUserName, null, component); + } + + /** + * Gets sentry privileges for a given roleName and Authorizable Hirerchys using the Sentry service + * @param requestorUserName: user on whose behalf the request is issued + * @param roleName: + * @param component: The request is issued to which component + * @param serviceName + * @param authorizables + * @return + * @throws SentryUserException + */ + public Set<TSentryPrivilege> listPrivilegesByRoleName( + String requestorUserName, String roleName, String component, + String serviceName, List<? extends Authorizable> authorizables) + throws SentryUserException { + TListSentryPrivilegesRequest request = new TListSentryPrivilegesRequest(); + request.setProtocol_version(sentry_common_serviceConstants.TSENTRY_SERVICE_V2); + request.setComponent(component); + request.setServiceName(serviceName); + request.setRequestorUserName(requestorUserName); + request.setRoleName(roleName); + if ((authorizables != null) && (authorizables.size() > 0)) { + List<TAuthorizable> tAuthorizables = Lists.newArrayList(); + for (Authorizable authorizable : authorizables) { + tAuthorizables.add(new TAuthorizable(authorizable.getTypeName(), authorizable.getName())); + } + request.setAuthorizables(tAuthorizables); + } + + TListSentryPrivilegesResponse response; + try { + response = client.list_sentry_privileges_by_role(request); + Status.throwIfNotOk(response.getStatus()); + } catch (TException e) { + throw new SentryUserException(THRIFT_EXCEPTION_MESSAGE, e); + } + return response.getPrivileges(); + } + + public Set<TSentryPrivilege> listPrivilegesByRoleName( + String requestorUserName, String roleName, String component, + String serviceName) throws SentryUserException { + return listPrivilegesByRoleName(requestorUserName, roleName, component, serviceName, null); + } + + /** + * get sentry permissions from provider as followings: + * @param: component: The request is issued to which component + * @param: serviceName: The privilege belongs to which service + * @param: roleSet + * @param: groupNames + * @param: the authorizables + * @returns the set of permissions + * @throws SentryUserException + */ + public Set<String> listPrivilegesForProvider(String component, + String serviceName, ActiveRoleSet roleSet, Set<String> groups, + List<? extends Authorizable> authorizables) throws SentryUserException { + TSentryActiveRoleSet thriftRoleSet = new TSentryActiveRoleSet(roleSet.isAll(), roleSet.getRoles()); + TListSentryPrivilegesForProviderRequest request = new TListSentryPrivilegesForProviderRequest(); + request.setProtocol_version(sentry_common_serviceConstants.TSENTRY_SERVICE_V2); + request.setComponent(component); + request.setServiceName(serviceName); + request.setRoleSet(thriftRoleSet); + if (groups == null) { + request.setGroups(new HashSet<String>()); + } else { + request.setGroups(groups); + } + List<TAuthorizable> tAuthoriables = Lists.newArrayList(); + if ((authorizables != null) && (authorizables.size() > 0)) { + for (Authorizable authorizable : authorizables) { + tAuthoriables.add(new TAuthorizable(authorizable.getTypeName(), authorizable.getName())); + } + request.setAuthorizables(tAuthoriables); + } + + try { + TListSentryPrivilegesForProviderResponse response = client.list_sentry_privileges_for_provider(request); + Status.throwIfNotOk(response.getStatus()); + return response.getPrivileges(); + } catch (TException e) { + throw new SentryUserException(THRIFT_EXCEPTION_MESSAGE, e); + } + } + + public void close() { + if (transport != null) { + transport.close(); + } + } +} http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/bf3eb482/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..266f349 --- /dev/null +++ b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/model/MSentryGMPrivilege.java @@ -0,0 +1,484 @@ +/** +vim * 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.provider.common.ProviderConstants.AUTHORIZABLE_JOINER; +import static org.apache.sentry.provider.common.ProviderConstants.KV_JOINER; + +import java.lang.reflect.Field; +import java.util.Arrays; +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 { + private static final String PREFIX_RESOURCE_NAME = "resourceName"; + private static final String PREFIX_RESOURCE_TYPE = "resourceType"; + private static final String NULL_COL = "__NULL__"; + private static final String SERVICE_SCOPE = "Server"; + private static final int AUTHORIZABLE_LEVEL = 4; + /** + * 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; + private String resourceType0 = NULL_COL; + private String resourceName1 = NULL_COL; + private String resourceType1 = NULL_COL; + private String resourceName2 = NULL_COL; + private String resourceType2 = NULL_COL; + private String resourceName3 = NULL_COL; + private String resourceType3 = NULL_COL; + + 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 = componentName; + this.serviceName = serviceName; + this.action = action; + this.grantOption = grantOption; + this.roles = new HashSet<MSentryRole>(); + 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>(); + for (MSentryRole role : copy.roles) { + roles.add(role); + } + } + + 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> other_authorizables = other.getAuthorizables(); + + if (authorizables.size() != other_authorizables.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(other_authorizables.get(i).getTypeName(), + other_authorizables.get(i).getName()); + if (!o1.equals(o2)) { + return false; + } + } + return true; + } + + /** + * Return true if this privilege implies request privilege + * Otherwise, return false + * @param other, 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); + } + } + + /** + * return the query to execute in JDO for search the given privilege + * @param privilege + * @return query + */ + public static String toQuery(MSentryGMPrivilege privilege) { + StringBuilder query = new StringBuilder(); + query.append("serviceName == \"" + toNULLCol(privilege.getServiceName()) + "\" "); + query.append("&& componentName == \"" + toNULLCol(privilege.getComponentName()) + "\" "); + query.append("&& scope == \"" + toNULLCol(privilege.getScope()) + "\" "); + query.append("&& action == \"" + toNULLCol(privilege.getAction()) + "\""); + if (privilege.getGrantOption() == null) { + query.append("&& this.grantOption == null "); + } else if (privilege.getGrantOption()) { + query.append("&& grantOption "); + } else { + query.append("&& !grantOption "); + } + List<? extends Authorizable> authorizables = privilege.getAuthorizables(); + for (int i = 0; i < AUTHORIZABLE_LEVEL; i++) { + String resourceName = PREFIX_RESOURCE_NAME + String.valueOf(i); + String resourceType = PREFIX_RESOURCE_TYPE + String.valueOf(i); + + if (i >= authorizables.size()) { + query.append("&& " + resourceName + " == \"" + NULL_COL + "\" "); + query.append("&& " + resourceType + " == \"" + NULL_COL + "\" "); + } else { + query.append("&& " + resourceName + " == \"" + authorizables.get(i).getName() + "\" "); + query.append("&& " + resourceType + " == \"" + authorizables.get(i).getTypeName() + "\" "); + } + } + return query.toString(); + } + + /** + * Get the query to execute in the JDO deducing privileges include the scope of according to the given privilege + * The query was used in three privilege operations: + * 1.revoking privilege + * 2.renaming privilege + * 3.dropping privilege + * Take the Solr for example, if there exists three privileges such as p1:Collection=c1->action=query, + * p2:Collection=c1->Field=f1->action=query and p3:Collection=c1->Field=f2->action=query. + * When the revoking operation happens, the request privilege is p4:Collection=c1->action=query. + * The result is that not only p1 should be revoked, but also p2 and p3 should be revoked together. + * So the populateIncludePrivilegesQuery should be Collection=c1 + * @param privilege + * @return query + */ + public static String populateIncludePrivilegesQuery(MSentryGMPrivilege privilege) { + StringBuilder query = new StringBuilder(); + query.append("serviceName == \"" + toNULLCol(privilege.getServiceName()) + "\" "); + query.append("&& componentName == \"" + toNULLCol(privilege.getComponentName()) + "\" "); + List<? extends Authorizable> authorizables = privilege.getAuthorizables(); + for (int i= 0 ; i < authorizables.size(); i++) { + String resourceName = PREFIX_RESOURCE_NAME + String.valueOf(i); + String resourceType = PREFIX_RESOURCE_TYPE + String.valueOf(i); + query.append("&& " + resourceName + " == \"" + authorizables.get(i).getName() + "\" "); + query.append("&& " + resourceType + " == \"" + authorizables.get(i).getTypeName() + "\" "); + } + return query.toString(); + } +} http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/bf3eb482/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/model/MSentryRole.java ---------------------------------------------------------------------- diff --git a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/model/MSentryRole.java b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/model/MSentryRole.java index bca9fb9..0076753 100644 --- a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/model/MSentryRole.java +++ b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/model/MSentryRole.java @@ -36,6 +36,9 @@ public class MSentryRole { private String roleName; // set of privileges granted to this role private Set<MSentryPrivilege> privileges; + // set of generic model privileges grant ro this role + private Set<MSentryGMPrivilege> gmPrivileges; + // set of groups this role belongs to private Set<MSentryGroup> groups; private long createTime; @@ -44,6 +47,7 @@ public class MSentryRole { this.roleName = roleName; this.createTime = createTime; privileges = new HashSet<MSentryPrivilege>(); + gmPrivileges = new HashSet<MSentryGMPrivilege>(); groups = new HashSet<MSentryGroup>(); } @@ -71,6 +75,14 @@ public class MSentryRole { return privileges; } + public Set<MSentryGMPrivilege> getGmPrivileges() { + return gmPrivileges; + } + + public void setGmPrivileges(Set<MSentryGMPrivilege> gmPrivileges) { + this.gmPrivileges = gmPrivileges; + } + public void setGroups(Set<MSentryGroup> groups) { this.groups = groups; } @@ -95,6 +107,25 @@ public class MSentryRole { } } + public void removeGMPrivilege(MSentryGMPrivilege gmPrivilege) { + if (gmPrivileges.remove(gmPrivilege)) { + gmPrivilege.removeRole(this); + } + } + + public void appendGMPrivilege(MSentryGMPrivilege gmPrivilege) { + if (gmPrivileges.add(gmPrivilege)) { + gmPrivilege.appendRole(this); + } + } + + public void removeGMPrivileges() { + for (MSentryGMPrivilege privilege : ImmutableSet.copyOf(gmPrivileges)) { + privilege.removeRole(this); + } + Preconditions.checkState(gmPrivileges.isEmpty(), "gmPrivileges should be empty: " + gmPrivileges); + } + public void appendGroups(Set<MSentryGroup> groups) { this.groups.addAll(groups); } @@ -121,7 +152,7 @@ public class MSentryRole { @Override public String toString() { - return "MSentryRole [roleName=" + roleName + ", privileges=[..]" + return "MSentryRole [roleName=" + roleName + ", privileges=[..]" + ", gmPrivileges=[..]" + ", groups=[...]" + ", createTime=" + createTime + "]"; } @@ -149,4 +180,5 @@ public class MSentryRole { return false; return true; } -} \ No newline at end of file + +} http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/bf3eb482/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/model/package.jdo ---------------------------------------------------------------------- diff --git a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/model/package.jdo b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/model/package.jdo index 594201f..d8f69b5 100644 --- a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/model/package.jdo +++ b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/model/package.jdo @@ -64,8 +64,18 @@ <element> <column name="DB_PRIVILEGE_ID"/> </element> - </field> - + </field> + + <field name = "gmPrivileges" table="SENTRY_ROLE_GM_PRIVILEGE_MAP" default-fetch-group="true"> + <collection element-type="org.apache.sentry.provider.db.service.model.MSentryGMPrivilege"/> + <join> + <column name="ROLE_ID"/> + </join> + <element> + <column name="GM_PRIVILEGE_ID"/> + </element> + </field> + <field name = "groups" table="SENTRY_ROLE_GROUP_MAP" > <collection element-type="org.apache.sentry.provider.db.service.model.MSentryGroup"/> <join> @@ -74,10 +84,10 @@ <element> <column name="GROUP_ID"/> </element> - </field> + </field> </class> - - <class name="MSentryPrivilege" identity-type="datastore" table="SENTRY_DB_PRIVILEGE" detachable="true"> + + <class name="MSentryPrivilege" identity-type="datastore" table="SENTRY_DB_PRIVILEGE" detachable="true"> <datastore-identity> <column name="DB_PRIVILEGE_ID"/> </datastore-identity> @@ -119,8 +129,74 @@ </field> <field name="roles" mapped-by="privileges"> <collection element-type="org.apache.sentry.provider.db.service.model.MSentryRole"/> - </field> + </field> </class> + + <class name="MSentryGMPrivilege" identity-type="datastore" table="SENTRY_GM_PRIVILEGE" detachable="true"> + <datastore-identity> + <column name="GM_PRIVILEGE_ID"/> + </datastore-identity> + <index name="GM_PRIVILEGE_INDEX" unique="true"> + <field name="componentName"/> + <field name="serviceName"/> + <field name="resourceName0"/> + <field name="resourceType0"/> + <field name="resourceName1"/> + <field name="resourceType1"/> + <field name="resourceName2"/> + <field name="resourceType2"/> + <field name="resourceName3"/> + <field name="resourceType3"/> + <field name="action"/> + <field name="grantOption"/> + </index> + <field name="componentName"> + <column name="COMPONENT_NAME" length="100" jdbc-type="VARCHAR"/> + </field> + <field name="serviceName"> + <column name="SERVICE_NAME" length="100" jdbc-type="VARCHAR"/> + </field> + <field name="resourceName0"> + <column name="RESOURCE_NAME_0" length="100" jdbc-type="VARCHAR"/> + </field> + <field name="resourceType0"> + <column name="RESOURCE_TYPE_0" length="100" jdbc-type="VARCHAR"/> + </field> + <field name="resourceName1"> + <column name="RESOURCE_NAME_1" length="100" jdbc-type="VARCHAR"/> + </field> + <field name="resourceType1"> + <column name="RESOURCE_TYPE_1" length="100" jdbc-type="VARCHAR"/> + </field> + <field name="resourceName2"> + <column name="RESOURCE_NAME_2" length="100" jdbc-type="VARCHAR"/> + </field> + <field name="resourceType2"> + <column name="RESOURCE_TYPE_2" length="100" jdbc-type="VARCHAR"/> + </field> + <field name="resourceName3"> + <column name="RESOURCE_NAME_3" length="100" jdbc-type="VARCHAR"/> + </field> + <field name="resourceType3"> + <column name="RESOURCE_TYPE_3" length="100" jdbc-type="VARCHAR"/> + </field> + <field name="action"> + <column name="ACTION" length="100" jdbc-type="VARCHAR"/> + </field> + <field name="scope"> + <column name="SCOPE" length="100" jdbc-type="VARCHAR"/> + </field> + <field name = "createTime"> + <column name = "CREATE_TIME" jdbc-type="BIGINT"/> + </field> + <field name="grantOption"> + <column name="WITH_GRANT_OPTION" length="1" jdbc-type="CHAR"/> + </field> + <field name="roles" mapped-by="gmPrivileges"> + <collection element-type="org.apache.sentry.provider.db.service.model.MSentryRole"/> + </field> + </class> + <class name="MSentryVersion" table="SENTRY_VERSION" identity-type="datastore" detachable="true"> <datastore-identity> <column name="VER_ID"/> http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/bf3eb482/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/persistent/SentryStore.java ---------------------------------------------------------------------- diff --git a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/persistent/SentryStore.java b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/persistent/SentryStore.java index f98e853..136dab6 100644 --- a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/persistent/SentryStore.java +++ b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/persistent/SentryStore.java @@ -219,7 +219,7 @@ public class SentryStore { * * Synchronized because we obtain persistence manager */ - private synchronized PersistenceManager openTransaction() { + public synchronized PersistenceManager openTransaction() { PersistenceManager pm = pmf.getPersistenceManager(); Transaction currentTransaction = pm.currentTransaction(); currentTransaction.begin(); @@ -229,7 +229,7 @@ public class SentryStore { /** * Synchronized due to sequence id generation */ - private synchronized CommitContext commitUpdateTransaction(PersistenceManager pm) { + public synchronized CommitContext commitUpdateTransaction(PersistenceManager pm) { commitTransaction(pm); return new CommitContext(SERVER_UUID, incrementGetSequenceId()); } @@ -244,7 +244,7 @@ public class SentryStore { return ++commitSequenceId; } - private void commitTransaction(PersistenceManager pm) { + public void commitTransaction(PersistenceManager pm) { Transaction currentTransaction = pm.currentTransaction(); try { Preconditions.checkState(currentTransaction.isActive(), "Transaction is not active"); @@ -254,7 +254,7 @@ public class SentryStore { } } - private void rollbackTransaction(PersistenceManager pm) { + public void rollbackTransaction(PersistenceManager pm) { if (pm == null || pm.isClosed()) { return; } @@ -271,7 +271,7 @@ public class SentryStore { Get the MSentry object from roleName Note: Should be called inside a transaction */ - private MSentryRole getMSentryRole(PersistenceManager pm, String roleName) { + public MSentryRole getMSentryRole(PersistenceManager pm, String roleName) { Query query = pm.newQuery(MSentryRole.class); query.setFilter("this.roleName == t"); query.declareParameters("java.lang.String t"); @@ -744,6 +744,8 @@ public class SentryStore { pm.retrieve(sentryRole); int numPrivs = sentryRole.getPrivileges().size(); sentryRole.removePrivileges(); + //with SENTRY-398 generic model + sentryRole.removeGMPrivileges(); privCleaner.incPrivRemoval(numPrivs); pm.deletePersistent(sentryRole); } @@ -1171,7 +1173,7 @@ public class SentryStore { } } - private Set<MSentryRole> getRolesForGroups(PersistenceManager pm, Set<String> groups) { + public Set<MSentryRole> getRolesForGroups(PersistenceManager pm, Set<String> groups) { Set<MSentryRole> result = new HashSet<MSentryRole>(); Query query = pm.newQuery(MSentryGroup.class); query.setFilter("this.groupName == t"); http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/bf3eb482/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/thrift/PolicyStoreConstants.java ---------------------------------------------------------------------- diff --git a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/thrift/PolicyStoreConstants.java b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/thrift/PolicyStoreConstants.java index 34bec93..1a1c0b7 100644 --- a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/thrift/PolicyStoreConstants.java +++ b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/thrift/PolicyStoreConstants.java @@ -18,7 +18,10 @@ package org.apache.sentry.provider.db.service.thrift; public class PolicyStoreConstants { - + public static final String SENTRY_GENERIC_POLICY_NOTIFICATION = "sentry.generic.policy.notification"; + public static final String SENTRY_GENERIC_POLICY_STORE = "sentry.generic.policy.store"; + public static final String SENTRY_GENERIC_POLICY_STORE_DEFAULT = + "org.apache.sentry.provider.db.generic.service.persistent.DelegateSentryStore"; public static class PolicyStoreServerConfig { public static final String NOTIFICATION_HANDLERS = "sentry.policy.store.notification.handlers"; } http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/bf3eb482/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/service/thrift/ServiceConstants.java ---------------------------------------------------------------------- diff --git a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/service/thrift/ServiceConstants.java b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/service/thrift/ServiceConstants.java index 56e0ce4..47794bc 100644 --- a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/service/thrift/ServiceConstants.java +++ b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/service/thrift/ServiceConstants.java @@ -67,7 +67,7 @@ public class ServiceConstants { public static final String RPC_MIN_THREADS = "sentry.service.server-min-threads"; public static final int RPC_MIN_THREADS_DEFAULT = 10; public static final String ALLOW_CONNECT = "sentry.service.allow.connect"; - + public static final String SENTRY_POLICY_STORE_PLUGINS = "sentry.policy.store.plugins"; public static final String SENTRY_POLICY_STORE_PLUGINS_DEFAULT = ""; @@ -76,7 +76,8 @@ public class ServiceConstants { public static final String PROCESSOR_FACTORIES = "sentry.service.processor.factories"; public static final String PROCESSOR_FACTORIES_DEFAULT = - "org.apache.sentry.provider.db.service.thrift.SentryPolicyStoreProcessorFactory"; + "org.apache.sentry.provider.db.service.thrift.SentryPolicyStoreProcessorFactory" + + ",org.apache.sentry.provider.db.generic.service.thrift.SentryGenericPolicyProcessorFactory"; public static final String SENTRY_STORE_JDBC_URL = "sentry.store.jdbc.url"; public static final String SENTRY_STORE_JDBC_USER = "sentry.store.jdbc.user"; public static final String SENTRY_STORE_JDBC_USER_DEFAULT = "Sentry"; http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/bf3eb482/sentry-provider/sentry-provider-db/src/main/resources/sentry_common_service.thrift ---------------------------------------------------------------------- diff --git a/sentry-provider/sentry-provider-db/src/main/resources/sentry_common_service.thrift b/sentry-provider/sentry-provider-db/src/main/resources/sentry_common_service.thrift index 9456274..956dabe 100644 --- a/sentry-provider/sentry-provider-db/src/main/resources/sentry_common_service.thrift +++ b/sentry-provider/sentry-provider-db/src/main/resources/sentry_common_service.thrift @@ -25,6 +25,7 @@ namespace php sentry.service.thrift namespace cpp Apache.Sentry.Service.Thrift const i32 TSENTRY_SERVICE_V1 = 1; +const i32 TSENTRY_SERVICE_V2 = 1; const i32 TSENTRY_STATUS_OK = 0; const i32 TSENTRY_STATUS_ALREADY_EXISTS = 1;
