http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/bf3eb482/sentry-provider/sentry-provider-db/src/gen/thrift/gen-javabean/org/apache/sentry/service/thrift/sentry_common_serviceConstants.java ---------------------------------------------------------------------- diff --git a/sentry-provider/sentry-provider-db/src/gen/thrift/gen-javabean/org/apache/sentry/service/thrift/sentry_common_serviceConstants.java b/sentry-provider/sentry-provider-db/src/gen/thrift/gen-javabean/org/apache/sentry/service/thrift/sentry_common_serviceConstants.java index 4fdeaeb..6c3d171 100644 --- a/sentry-provider/sentry-provider-db/src/gen/thrift/gen-javabean/org/apache/sentry/service/thrift/sentry_common_serviceConstants.java +++ b/sentry-provider/sentry-provider-db/src/gen/thrift/gen-javabean/org/apache/sentry/service/thrift/sentry_common_serviceConstants.java @@ -35,6 +35,8 @@ public class sentry_common_serviceConstants { public static final int TSENTRY_SERVICE_V1 = 1; + public static final int TSENTRY_SERVICE_V2 = 1; + public static final int TSENTRY_STATUS_OK = 0; public static final int TSENTRY_STATUS_ALREADY_EXISTS = 1;
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/persistent/DelegateSentryStore.java ---------------------------------------------------------------------- diff --git a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/generic/service/persistent/DelegateSentryStore.java b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/generic/service/persistent/DelegateSentryStore.java new file mode 100644 index 0000000..b81360b --- /dev/null +++ b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/generic/service/persistent/DelegateSentryStore.java @@ -0,0 +1,447 @@ +/** + * 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.persistent; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Set; + +import javax.jdo.PersistenceManager; +import javax.jdo.Query; + +import org.apache.hadoop.conf.Configuration; +import org.apache.sentry.SentryUserException; +import org.apache.sentry.core.common.Authorizable; +import org.apache.sentry.provider.db.SentryAccessDeniedException; +import org.apache.sentry.provider.db.SentryAlreadyExistsException; +import org.apache.sentry.provider.db.SentryGrantDeniedException; +import org.apache.sentry.provider.db.SentryInvalidInputException; +import org.apache.sentry.provider.db.SentryNoSuchObjectException; +import org.apache.sentry.provider.db.service.model.MSentryGroup; +import org.apache.sentry.provider.db.service.model.MSentryRole; +import org.apache.sentry.provider.db.service.persistent.CommitContext; +import org.apache.sentry.provider.db.service.persistent.SentryStore; +import org.apache.sentry.provider.db.service.thrift.SentryPolicyStoreProcessor; +import org.apache.sentry.provider.db.service.thrift.TSentryGroup; +import org.apache.sentry.provider.db.service.thrift.TSentryRole; +import org.apache.sentry.service.thrift.ServiceConstants.ServerConfig; + +import com.google.common.base.Joiner; +import com.google.common.base.Preconditions; +import com.google.common.base.Strings; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Sets; + +/** + * The DelegateSentryStore will supports the generic authorizable model. It stores the authorizables + * into separated column. Take the authorizables:[DATABASE=db1,TABLE=tb1,COLUMN=cl1] for example, + * The DATABASE,db1,TABLE,tb1,COLUMN and cl1 will be stored into the six columns(resourceName0=db1,resourceType0=DATABASE, + * resourceName1=tb1,resourceType1=TABLE, + * resourceName2=cl1,resourceType2=COLUMN ) of generic privilege table + */ +public class DelegateSentryStore implements SentryStoreLayer { + private SentryStore delegate; + private Configuration conf; + private Set<String> adminGroups; + private PrivilegeOperatePersistence privilegeOperator; + + public DelegateSentryStore(Configuration conf) throws SentryNoSuchObjectException, + SentryAccessDeniedException { + this.privilegeOperator = new PrivilegeOperatePersistence(); + // The generic model doesn't turn on the thread that cleans hive privileges + conf.set(ServerConfig.SENTRY_STORE_ORPHANED_PRIVILEGE_REMOVAL,"false"); + this.conf = conf; + //delegated old sentryStore + this.delegate = new SentryStore(conf); + adminGroups = ImmutableSet.copyOf(toTrimedLower(Sets.newHashSet(conf.getStrings( + ServerConfig.ADMIN_GROUPS, new String[]{})))); + } + + private PersistenceManager openTransaction() { + return delegate.openTransaction(); + } + + private CommitContext commitUpdateTransaction(PersistenceManager pm) { + return delegate.commitUpdateTransaction(pm); + } + + private void rollbackTransaction(PersistenceManager pm) { + delegate.rollbackTransaction(pm); + } + + private void commitTransaction(PersistenceManager pm) { + delegate.commitTransaction(pm); + } + + private MSentryRole getRole(String roleName, PersistenceManager pm) { + return delegate.getMSentryRole(pm, roleName); + } + + @Override + public CommitContext createRole(String component, String role, + String requestor) throws SentryAlreadyExistsException { + return delegate.createSentryRole(role); + } + + /** + * The role is global in the generic model, such as the role may be has more than one component + * privileges, so delete role will remove all privileges related to it. + */ + @Override + public CommitContext dropRole(String component, String role, String requestor) + throws SentryNoSuchObjectException { + boolean rollbackTransaction = true; + PersistenceManager pm = null; + role = toTrimedLower(role); + try { + pm = openTransaction(); + Query query = pm.newQuery(MSentryRole.class); + query.setFilter("this.roleName == t"); + query.declareParameters("java.lang.String t"); + query.setUnique(true); + MSentryRole sentryRole = (MSentryRole) query.execute(role); + if (sentryRole == null) { + throw new SentryNoSuchObjectException("Role " + role); + } else { + pm.retrieve(sentryRole); + sentryRole.removeGMPrivileges(); + sentryRole.removePrivileges(); + pm.deletePersistent(sentryRole); + } + CommitContext commit = commitUpdateTransaction(pm); + rollbackTransaction = false; + return commit; + } finally { + if (rollbackTransaction) { + rollbackTransaction(pm); + } + } + } + + @Override + public CommitContext alterRoleAddGroups(String component, String role, + Set<String> groups, String requestor) throws SentryNoSuchObjectException { + return delegate.alterSentryRoleAddGroups(requestor, role, toTSentryGroups(groups)); + } + + @Override + public CommitContext alterRoleDeleteGroups(String component, String role, + Set<String> groups, String requestor) throws SentryNoSuchObjectException { + //called to old sentryStore + return delegate.alterSentryRoleDeleteGroups(role, toTSentryGroups(groups)); + } + + @Override + public CommitContext alterRoleGrantPrivilege(String component, String role, + PrivilegeObject privilege, String grantorPrincipal) + throws SentryUserException { + role = toTrimedLower(role); + PersistenceManager pm = null; + boolean rollbackTransaction = true; + try{ + pm = openTransaction(); + MSentryRole mRole = getRole(role, pm); + if (mRole == null) { + throw new SentryNoSuchObjectException("role:" + role + " isn't exist"); + } + /** + * check with grant option + */ + grantOptionCheck(privilege, grantorPrincipal, pm); + + privilegeOperator.grantPrivilege(privilege, mRole, pm); + + CommitContext commitContext = delegate.commitUpdateTransaction(pm); + rollbackTransaction = false; + return commitContext; + + } finally { + if (rollbackTransaction) { + rollbackTransaction(pm); + } + } + } + + @Override + public CommitContext alterRoleRevokePrivilege(String component, + String role, PrivilegeObject privilege, String grantorPrincipal) + throws SentryUserException { + role = toTrimedLower(role); + PersistenceManager pm = null; + boolean rollbackTransaction = true; + try{ + pm = openTransaction(); + MSentryRole mRole = getRole(role, pm); + if (mRole == null) { + throw new SentryNoSuchObjectException("role:" + role + " isn't exist"); + } + /** + * check with grant option + */ + grantOptionCheck(privilege, grantorPrincipal, pm); + + privilegeOperator.revokePrivilege(privilege, mRole, pm); + + CommitContext commitContext = commitUpdateTransaction(pm); + rollbackTransaction = false; + return commitContext; + + } finally { + if (rollbackTransaction) { + rollbackTransaction(pm); + } + } + } + + @Override + public CommitContext renamePrivilege(String component, String service, + List<? extends Authorizable> oldAuthorizables, + List<? extends Authorizable> newAuthorizables, String requestor) + throws SentryUserException { + Preconditions.checkNotNull(component); + Preconditions.checkNotNull(service); + Preconditions.checkNotNull(oldAuthorizables); + Preconditions.checkNotNull(newAuthorizables); + + if (oldAuthorizables.size() != newAuthorizables.size()) { + throw new SentryAccessDeniedException( + "rename privilege denied: the size of oldAuthorizables must equals the newAuthorizables " + + "oldAuthorizables:" + Arrays.toString(oldAuthorizables.toArray()) + " " + + "newAuthorizables:" + Arrays.toString(newAuthorizables.toArray())); + } + + PersistenceManager pm = null; + boolean rollbackTransaction = true; + try { + pm = openTransaction(); + + privilegeOperator.renamePrivilege(toTrimedLower(component), toTrimedLower(service), + oldAuthorizables, newAuthorizables, requestor, pm); + + CommitContext commitContext = commitUpdateTransaction(pm); + rollbackTransaction = false; + return commitContext; + } finally { + if (rollbackTransaction) { + rollbackTransaction(pm); + } + } + } + + @Override + public CommitContext dropPrivilege(String component, + PrivilegeObject privilege, String requestor) throws SentryUserException { + Preconditions.checkNotNull(requestor); + + PersistenceManager pm = null; + boolean rollbackTransaction = true; + try { + pm = openTransaction(); + + privilegeOperator.dropPrivilege(privilege, pm); + + CommitContext commitContext = commitUpdateTransaction(pm); + rollbackTransaction = false; + return commitContext; + } finally { + if (rollbackTransaction) { + rollbackTransaction(pm); + } + } + } + + /** + * Grant option check + * @param component + * @param pm + * @param privilegeReader + * @throws SentryUserException + */ + private void grantOptionCheck(PrivilegeObject requestPrivilege, String grantorPrincipal,PersistenceManager pm) + throws SentryUserException { + + if (Strings.isNullOrEmpty(grantorPrincipal)) { + throw new SentryInvalidInputException("grantorPrincipal should not be null or empty"); + } + + Set<String> groups = getRequestorGroups(grantorPrincipal); + if (groups == null || groups.isEmpty()) { + throw new SentryGrantDeniedException(grantorPrincipal + + " has no grant!"); + } + //admin group check + if (!Sets.intersection(adminGroups, toTrimedLower(groups)).isEmpty()) { + return; + } + //privilege grant option check + Set<MSentryRole> mRoles = delegate.getRolesForGroups(pm, groups); + if (!privilegeOperator.checkPrivilegeOption(mRoles, requestPrivilege, pm)) { + throw new SentryGrantDeniedException(grantorPrincipal + + " has no grant!"); + } + } + + @Override + public Set<String> getRolesByGroups(String component, Set<String> groups) + throws SentryUserException { + Set<String> roles = Sets.newHashSet(); + if (groups == null) { + return roles; + } + for (TSentryRole tSentryRole : delegate.getTSentryRolesByGroupName(groups, true)) { + roles.add(tSentryRole.getRoleName()); + } + return roles; + } + + @Override + public Set<String> getGroupsByRoles(String component, Set<String> roles) + throws SentryUserException { + roles = toTrimedLower(roles); + Set<String> groupNames = Sets.newHashSet(); + if (roles.size() == 0) return groupNames; + + PersistenceManager pm = null; + try{ + pm = openTransaction(); + //get groups by roles + Query query = pm.newQuery(MSentryGroup.class); + StringBuilder filters = new StringBuilder(); + query.declareVariables("org.apache.sentry.provider.db.service.model.MSentryRole role"); + List<String> rolesFiler = new LinkedList<String>(); + for (String role : roles) { + rolesFiler.add("role.roleName == \"" + role + "\" "); + } + filters.append("roles.contains(role) " + "&& (" + Joiner.on(" || ").join(rolesFiler) + ")"); + query.setFilter(filters.toString()); + + List<MSentryGroup> groups = (List<MSentryGroup>)query.execute(); + if (groups == null) { + return groupNames; + } + for (MSentryGroup group : groups) { + groupNames.add(group.getGroupName()); + } + return groupNames; + } finally { + commitTransaction(pm); + } + } + + @Override + public Set<PrivilegeObject> getPrivilegesByRole(String component, + Set<String> roles) throws SentryUserException { + Preconditions.checkNotNull(roles); + Set<PrivilegeObject> privileges = Sets.newHashSet(); + if (roles.isEmpty()) return privileges; + + PersistenceManager pm = null; + try { + pm = openTransaction(); + Set<MSentryRole> mRoles = Sets.newHashSet(); + for (String role : roles) { + MSentryRole mRole = getRole(toTrimedLower(role), pm); + if (mRole != null) { + mRoles.add(mRole); + } + } + privileges.addAll(privilegeOperator.getPrivilegesByRole(mRoles, pm)); + } finally { + commitTransaction(pm); + } + return privileges; + } + + @Override + public Set<PrivilegeObject> getPrivilegesByProvider(String component, + String service, Set<String> roles, Set<String> groups, + List<? extends Authorizable> authorizables) throws SentryUserException { + Preconditions.checkNotNull(component); + Preconditions.checkNotNull(service); + + component = toTrimedLower(component); + service = toTrimedLower(service); + + Set<PrivilegeObject> privileges = Sets.newHashSet(); + PersistenceManager pm = null; + try { + pm = openTransaction(); + //CaseInsensitive roleNames + roles = toTrimedLower(roles); + + if (groups != null) { + roles.addAll(delegate.getRoleNamesForGroups(groups)); + } + + if (roles.size() == 0) { + return privileges; + } + + Set<MSentryRole> mRoles = Sets.newHashSet(); + for (String role : roles) { + MSentryRole mRole = getRole(role, pm); + if (mRole != null) { + mRoles.add(mRole); + } + } + //get the privileges + privileges.addAll(privilegeOperator.getPrivilegesByProvider(component, service, mRoles, authorizables, pm)); + } finally { + commitTransaction(pm); + } + return privileges; + } + + @Override + public void close() { + delegate.stop(); + } + + private Set<TSentryGroup> toTSentryGroups(Set<String> groups) { + Set<TSentryGroup> tSentryGroups = Sets.newHashSet(); + for (String group : toTrimedLower(groups)) { + tSentryGroups.add(new TSentryGroup(group)); + } + return tSentryGroups; + } + + private Set<String> toTrimedLower(Set<String> s) { + if (s == null) { + 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 (s == null) { + return ""; + } + return s.trim().toLowerCase(); + } + + private Set<String> getRequestorGroups(String userName) + throws SentryUserException { + return SentryPolicyStoreProcessor.getGroupsFromUserName(this.conf, userName); + } +} 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/persistent/PrivilegeObject.java ---------------------------------------------------------------------- diff --git a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/generic/service/persistent/PrivilegeObject.java b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/generic/service/persistent/PrivilegeObject.java new file mode 100644 index 0000000..aa56207 --- /dev/null +++ b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/generic/service/persistent/PrivilegeObject.java @@ -0,0 +1,221 @@ +/** + * 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.persistent; + +import static org.apache.sentry.provider.common.ProviderConstants.KV_JOINER; +import static org.apache.sentry.provider.common.ProviderConstants.AUTHORIZABLE_JOINER; + +import java.util.ArrayList; +import java.util.List; +import org.apache.sentry.core.common.Authorizable; +import com.google.common.base.Preconditions; +import com.google.common.collect.Lists; + +public class PrivilegeObject { + private final String component; + private final String service; + private final String action; + private final Boolean grantOption; + private List<? extends Authorizable> authorizables; + + private PrivilegeObject(String component, String service, String action, + Boolean grantOption, + List<? extends Authorizable> authorizables) { + this.component = component; + this.service = service; + this.action = action; + this.grantOption = grantOption; + this.authorizables = authorizables; + } + + public List<? extends Authorizable> getAuthorizables() { + return authorizables; + } + + public String getAction() { + return action; + } + + public String getComponent() { + return component; + } + + public String getService() { + return service; + } + + public Boolean getGrantOption() { + return grantOption; + } + + @Override + public String toString() { + List<String> authorizable = Lists.newArrayList(); + for (Authorizable az : authorizables) { + authorizable.add(KV_JOINER.join(az.getTypeName(),az.getName())); + } + return "PrivilegeObject [" + ", service=" + service + ", component=" + + component + ", authorizables=" + AUTHORIZABLE_JOINER.join(authorizable) + + ", action=" + action + ", grantOption=" + grantOption + "]"; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((action == null) ? 0 : action.hashCode()); + result = prime * result + ((component == null) ? 0 : component.hashCode()); + result = prime * result + ((service == null) ? 0 : service.hashCode()); + result = prime * result + ((grantOption == null) ? 0 : grantOption.hashCode()); + for (Authorizable authorizable : authorizables) { + result = prime * result + authorizable.getTypeName().hashCode(); + result = prime * result + authorizable.getName().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; + PrivilegeObject other = (PrivilegeObject) obj; + if (action == null) { + if (other.action != null) + return false; + } else if (!action.equals(other.action)) + return false; + if (service == null) { + if (other.service != null) + return false; + } else if (!service.equals(other.service)) + return false; + if (component == null) { + if (other.component != null) + return false; + } else if (!component.equals(other.component)) + return false; + if (grantOption == null) { + if (other.grantOption != null) + return false; + } else if (!grantOption.equals(other.grantOption)) + return false; + + 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.equalsIgnoreCase(o2)) { + return false; + } + } + return true; + } + + public static class Builder { + private String component; + private String service; + private String action; + private Boolean grantOption; + private List<? extends Authorizable> authorizables; + + public Builder() { + + } + + public Builder(PrivilegeObject privilege) { + this.component = privilege.component; + this.service = privilege.service; + this.action = privilege.action; + this.grantOption = privilege.grantOption; + this.authorizables = privilege.authorizables; + } + + public Builder setComponent(String component) { + this.component = component; + return this; + } + + public Builder setService(String service) { + this.service = service; + return this; + } + + public Builder setAction(String action) { + this.action = action; + return this; + } + + public Builder withGrantOption(Boolean grantOption) { + this.grantOption = grantOption; + return this; + } + + public Builder setAuthorizables(List<? extends Authorizable> authorizables) { + this.authorizables = authorizables; + return this; + } + + /** + * TolowerCase the authorizable name, the authorizable type is define when it was created. + * Take the Solr for example, it has two Authorizable objects. They have the type Collection + * and Field, they are can't be changed. So we should unified the authorizable name tolowercase. + * @return new authorizable lists + */ + private List<? extends Authorizable> toLowerAuthorizableName(List<? extends Authorizable> authorizables) { + List<Authorizable> newAuthorizable = Lists.newArrayList(); + if ((authorizables == null) || (authorizables.size() == 0)) { + return newAuthorizable; + } + for (final Authorizable authorizable : authorizables) { + newAuthorizable.add(new Authorizable() { + @Override + public String getTypeName() { + return authorizable.getTypeName(); + } + @Override + public String getName() { + return authorizable.getName().toLowerCase(); + } + }); + } + return newAuthorizable; + } + + public PrivilegeObject build() { + Preconditions.checkNotNull(component); + Preconditions.checkNotNull(service); + Preconditions.checkNotNull(action); + //CaseInsensitive authorizable name + List<? extends Authorizable> newAuthorizable = toLowerAuthorizableName(authorizables); + + return new PrivilegeObject(component.toLowerCase(), + service.toLowerCase(), + action.toLowerCase(), + grantOption, + newAuthorizable); + } + } +} 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/persistent/PrivilegeOperatePersistence.java ---------------------------------------------------------------------- diff --git a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/generic/service/persistent/PrivilegeOperatePersistence.java b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/generic/service/persistent/PrivilegeOperatePersistence.java new file mode 100644 index 0000000..dab7d74 --- /dev/null +++ b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/generic/service/persistent/PrivilegeOperatePersistence.java @@ -0,0 +1,413 @@ +/** + * 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.persistent; + +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import javax.jdo.PersistenceManager; +import javax.jdo.Query; + +import org.apache.sentry.SentryUserException; +import org.apache.sentry.core.common.Action; +import org.apache.sentry.core.common.Authorizable; +import org.apache.sentry.core.common.BitFieldAction; +import org.apache.sentry.core.common.BitFieldActionFactory; +import org.apache.sentry.core.model.search.SearchActionFactory; +import org.apache.sentry.provider.db.generic.service.persistent.PrivilegeObject.Builder; +import org.apache.sentry.provider.db.service.model.MSentryGMPrivilege; +import org.apache.sentry.provider.db.service.model.MSentryRole; + +import com.google.common.base.Joiner; +import com.google.common.base.Strings; +import com.google.common.collect.Maps; +import com.google.common.collect.Sets; + +/** + * This class used do some operations related privilege and make the results + * persistence + */ +public class PrivilegeOperatePersistence { + private static final Map<String, BitFieldActionFactory> actionFactories = Maps.newHashMap(); + static{ + actionFactories.put("solr", new SearchActionFactory()); + } + + public boolean checkPrivilegeOption(Set<MSentryRole> roles, PrivilegeObject privilege, PersistenceManager pm) { + MSentryGMPrivilege requestPrivilege = convertToPrivilege(privilege); + boolean hasGrant = false; + //get persistent privileges by roles + Query query = pm.newQuery(MSentryGMPrivilege.class); + StringBuilder filters = new StringBuilder(); + if ((roles != null) && (roles.size() > 0)) { + query.declareVariables("org.apache.sentry.provider.db.service.model.MSentryRole role"); + List<String> rolesFiler = new LinkedList<String>(); + for (MSentryRole role : roles) { + rolesFiler.add("role.roleName == \"" + role.getRoleName() + "\" "); + } + filters.append("roles.contains(role) " + "&& (" + Joiner.on(" || ").join(rolesFiler) + ")"); + } + query.setFilter(filters.toString()); + + List<MSentryGMPrivilege> tPrivileges = (List<MSentryGMPrivilege>)query.execute(); + for (MSentryGMPrivilege tPrivilege : tPrivileges) { + if (tPrivilege.getGrantOption() && tPrivilege.implies(requestPrivilege)) { + hasGrant = true; + break; + } + } + return hasGrant; + } + public void grantPrivilege(PrivilegeObject privilege,MSentryRole role, PersistenceManager pm) throws SentryUserException { + MSentryGMPrivilege mPrivilege = convertToPrivilege(privilege); + grantRolePartial(mPrivilege, role, pm); + } + + private void grantRolePartial(MSentryGMPrivilege grantPrivilege, + MSentryRole role,PersistenceManager pm) { + /** + * If Grant is for ALL action and other actions belongs to ALL action already exists.. + * need to remove it and GRANT ALL action + */ + String component = grantPrivilege.getComponentName(); + BitFieldAction action = getAction(component, grantPrivilege.getAction()); + BitFieldAction allAction = getAction(component, Action.ALL); + + if (action.implies(allAction)) { + /** + * ALL action is a multi-bit set action that includes some actions such as INSERT,SELECT and CREATE. + */ + List<? extends BitFieldAction> actions = getActionFactory(component).getActionsByCode(allAction.getActionCode()); + for (BitFieldAction ac : actions) { + grantPrivilege.setAction(ac.getValue()); + MSentryGMPrivilege existPriv = getPrivilege(grantPrivilege, pm); + if ((existPriv != null) && (role.getGmPrivileges().contains(existPriv))) { + /** + * force to load all roles related this privilege + * avoid the lazy-loading risk,such as: + * if the roles field of privilege aren't loaded, then the roles is a empty set + * privilege.removeRole(role) and pm.makePersistent(privilege) + * will remove other roles that shouldn't been removed + */ + pm.retrieve(existPriv); + existPriv.removeRole(role); + pm.makePersistent(existPriv); + } + } + } else { + /** + * If ALL Action already exists.. + * do nothing. + */ + grantPrivilege.setAction(allAction.getValue()); + MSentryGMPrivilege allPrivilege = getPrivilege(grantPrivilege, pm); + if ((allPrivilege != null) && (role.getGmPrivileges().contains(allPrivilege))) { + return; + } + } + + /** + * restore the action + */ + grantPrivilege.setAction(action.getValue()); + /** + * check the privilege is exist or not + */ + MSentryGMPrivilege mPrivilege = getPrivilege(grantPrivilege, pm); + if (mPrivilege == null) { + mPrivilege = grantPrivilege; + } + mPrivilege.appendRole(role); + pm.makePersistent(mPrivilege); + } + + + public void revokePrivilege(PrivilegeObject privilege,MSentryRole role, PersistenceManager pm) throws SentryUserException { + MSentryGMPrivilege mPrivilege = getPrivilege(convertToPrivilege(privilege), pm); + if (mPrivilege == null) { + mPrivilege = convertToPrivilege(privilege); + } + + Set<MSentryGMPrivilege> privilegeGraph = Sets.newHashSet(); + privilegeGraph.addAll(populateIncludePrivileges(Sets.newHashSet(role), mPrivilege, pm)); + + /** + * Get the privilege graph + * populateIncludePrivileges will get the privileges that needed revoke + */ + for (MSentryGMPrivilege persistedPriv : privilegeGraph) { + /** + * force to load all roles related this privilege + * avoid the lazy-loading risk,such as: + * if the roles field of privilege aren't loaded, then the roles is a empty set + * privilege.removeRole(role) and pm.makePersistent(privilege) + * will remove other roles that shouldn't been removed + */ + pm.retrieve(persistedPriv); + + revokeRolePartial(mPrivilege, persistedPriv, role, pm); + } + } + + /** + * Explore Privilege graph and collect privileges that are belong to the specific privilege + */ + @SuppressWarnings("unchecked") + private Set<MSentryGMPrivilege> populateIncludePrivileges(Set<MSentryRole> roles, + MSentryGMPrivilege parent, PersistenceManager pm) { + Set<MSentryGMPrivilege> childrens = Sets.newHashSet(); + + Query query = pm.newQuery(MSentryGMPrivilege.class); + StringBuilder filters = new StringBuilder(); + //add populateIncludePrivilegesQuery + filters.append(MSentryGMPrivilege.populateIncludePrivilegesQuery(parent)); + // add filter for role names + if ((roles != null) && (roles.size() > 0)) { + query.declareVariables("org.apache.sentry.provider.db.service.model.MSentryRole role"); + List<String> rolesFiler = new LinkedList<String>(); + for (MSentryRole role : roles) { + rolesFiler.add("role.roleName == \"" + role.getRoleName() + "\" "); + } + filters.append("&& roles.contains(role) " + "&& (" + Joiner.on(" || ").join(rolesFiler) + ")"); + } + query.setFilter(filters.toString()); + + List<MSentryGMPrivilege> privileges = (List<MSentryGMPrivilege>)query.execute(); + childrens.addAll(privileges); + return childrens; + } + + /** + * Roles can be granted multi-bit set action like ALL action on resource object. + * Take solr component for example, When a role has been granted ALL action but + * QUERY or UPDATE or CREATE are revoked, we need to remove the ALL + * privilege and add left privileges like UPDATE and CREATE(QUERY was revoked) or + * QUERY and UPDATE(CREATEE was revoked). + */ + private void revokeRolePartial(MSentryGMPrivilege revokePrivilege, + MSentryGMPrivilege persistedPriv, MSentryRole role, + PersistenceManager pm) { + String component = revokePrivilege.getComponentName(); + BitFieldAction revokeaction = getAction(component, revokePrivilege.getAction()); + BitFieldAction persistedAction = getAction(component, persistedPriv.getAction()); + BitFieldAction allAction = getAction(component, Action.ALL); + + if (revokeaction.implies(allAction)) { + /** + * if revoke action is ALL, directly revoke its children privileges and itself + */ + persistedPriv.removeRole(role); + pm.makePersistent(persistedPriv); + } else { + /** + * if persisted action is ALL, it only revoke the requested action and left partial actions + * like the requested action is SELECT, the UPDATE and CREATE action are left + */ + if (persistedAction.implies(allAction)) { + /** + * revoke the ALL privilege + */ + persistedPriv.removeRole(role); + pm.makePersistent(persistedPriv); + + List<? extends BitFieldAction> actions = getActionFactory(component).getActionsByCode(allAction.getActionCode()); + for (BitFieldAction ac: actions) { + if (ac.getActionCode() != revokeaction.getActionCode()) { + /** + * grant the left privileges to role + */ + MSentryGMPrivilege leftPriv = new MSentryGMPrivilege(persistedPriv); + leftPriv.setAction(ac.getValue()); + leftPriv.appendRole(role); + pm.makePersistent(leftPriv); + } + } + } else if (revokeaction.implies(persistedAction)) { + /** + * if the revoke action is equal to the persisted action and they aren't ALL action + * directly remove the role from privilege + */ + persistedPriv.removeRole(role); + pm.makePersistent(persistedPriv); + } else { + /** + * if the revoke action is not equal to the persisted action, + * do nothing + */ + } + } + } + + /** + * Drop any role related to the requested privilege and its children privileges + */ + public void dropPrivilege(PrivilegeObject privilege,PersistenceManager pm) { + MSentryGMPrivilege requestPrivilege = convertToPrivilege(privilege); + + if (Strings.isNullOrEmpty(privilege.getAction())) { + requestPrivilege.setAction(getAction(privilege.getComponent(), Action.ALL).getValue()); + } + /** + * Get the privilege graph + * populateIncludePrivileges will get the privileges that need dropped, + */ + Set<MSentryGMPrivilege> privilegeGraph = Sets.newHashSet(); + privilegeGraph.addAll(populateIncludePrivileges(null, requestPrivilege, pm)); + + for (MSentryGMPrivilege mPrivilege : privilegeGraph) { + /** + * force to load all roles related this privilege + * avoid the lazy-loading + */ + pm.retrieve(mPrivilege); + Set<MSentryRole> roles = mPrivilege.getRoles(); + for (MSentryRole role : roles) { + revokeRolePartial(requestPrivilege, mPrivilege, role, pm); + } + } + } + + private MSentryGMPrivilege convertToPrivilege(PrivilegeObject privilege) { + return new MSentryGMPrivilege(privilege.getComponent(), + privilege.getService(), privilege.getAuthorizables(), + privilege.getAction(), privilege.getGrantOption()); + } + + private MSentryGMPrivilege getPrivilege(MSentryGMPrivilege privilege, PersistenceManager pm) { + Query query = pm.newQuery(MSentryGMPrivilege.class); + query.setFilter(MSentryGMPrivilege.toQuery(privilege)); + query.setUnique(true); + return (MSentryGMPrivilege)query.execute(); + } + + @SuppressWarnings("unchecked") + public Set<PrivilegeObject> getPrivilegesByRole(Set<MSentryRole> roles, PersistenceManager pm) { + Set<PrivilegeObject> privileges = Sets.newHashSet(); + if ((roles == null) || (roles.size() == 0)) { + return privileges; + } + Query query = pm.newQuery(MSentryGMPrivilege.class); + StringBuilder filters = new StringBuilder(); + // add filter for role names + query.declareVariables("org.apache.sentry.provider.db.service.model.MSentryRole role"); + List<String> rolesFiler = new LinkedList<String>(); + for (MSentryRole role : roles) { + rolesFiler.add("role.roleName == \"" + role.getRoleName() + "\" "); + } + filters.append("roles.contains(role) " + "&& (" + Joiner.on(" || ").join(rolesFiler) + ")"); + + query.setFilter(filters.toString()); + List<MSentryGMPrivilege> mPrivileges = (List<MSentryGMPrivilege>) query.execute(); + if ((mPrivileges == null) || (mPrivileges.size() ==0)) { + return privileges; + } + for (MSentryGMPrivilege mPrivilege : mPrivileges) { + privileges.add(new Builder() + .setComponent(mPrivilege.getComponentName()) + .setService(mPrivilege.getServiceName()) + .setAction(mPrivilege.getAction()) + .setAuthorizables(mPrivilege.getAuthorizables()) + .withGrantOption(mPrivilege.getGrantOption()) + .build()); + } + return privileges; + } + + public Set<PrivilegeObject> getPrivilegesByProvider(String component, + String service, Set<MSentryRole> roles, + List<? extends Authorizable> authorizables, PersistenceManager pm) { + Set<PrivilegeObject> privileges = Sets.newHashSet(); + if ((roles == null) || (roles.size() == 0)) return privileges; + + MSentryGMPrivilege parentPrivilege = new MSentryGMPrivilege(component, service, authorizables, null, null); + Set<MSentryGMPrivilege> privilegeGraph = Sets.newHashSet(); + privilegeGraph.addAll(populateIncludePrivileges(roles, parentPrivilege, pm)); + + for (MSentryGMPrivilege mPrivilege : privilegeGraph) { + privileges.add(new Builder() + .setComponent(mPrivilege.getComponentName()) + .setService(mPrivilege.getServiceName()) + .setAction(mPrivilege.getAction()) + .setAuthorizables(mPrivilege.getAuthorizables()) + .withGrantOption(mPrivilege.getGrantOption()) + .build()); + } + return privileges; + } + + + public void renamePrivilege(String component, String service, + List<? extends Authorizable> oldAuthorizables, List<? extends Authorizable> newAuthorizables, + String grantorPrincipal, PersistenceManager pm) + throws SentryUserException { + MSentryGMPrivilege oldPrivilege = new MSentryGMPrivilege(component, service, oldAuthorizables, null, null); + oldPrivilege.setAction(getAction(component,Action.ALL).getValue()); + /** + * Get the privilege graph + * populateIncludePrivileges will get the old privileges that need dropped + */ + Set<MSentryGMPrivilege> privilegeGraph = Sets.newHashSet(); + privilegeGraph.addAll(populateIncludePrivileges(null, oldPrivilege, pm)); + + for (MSentryGMPrivilege dropPrivilege : privilegeGraph) { + /** + * construct the new privilege needed to add + */ + List<Authorizable> authorizables = new ArrayList<Authorizable>( + dropPrivilege.getAuthorizables()); + for (int i = 0; i < newAuthorizables.size(); i++) { + authorizables.set(i, newAuthorizables.get(i)); + } + MSentryGMPrivilege newPrivilge = new MSentryGMPrivilege( + component,service, authorizables, dropPrivilege.getAction(), + dropPrivilege.getGrantOption()); + + /** + * force to load all roles related this privilege + * avoid the lazy-loading + */ + pm.retrieve(dropPrivilege); + + Set<MSentryRole> roles = dropPrivilege.getRoles(); + for (MSentryRole role : roles) { + revokeRolePartial(oldPrivilege, dropPrivilege, role, pm); + grantRolePartial(newPrivilge, role, pm); + } + } + } + + public static BitFieldAction getAction(String component, String name) { + BitFieldActionFactory actionFactory = getActionFactory(component); + BitFieldAction action = actionFactory.getActionByName(name); + if (action == null) { + throw new RuntimeException("can't get BitFieldAction for name:" + name); + } + return action; + } + + public static BitFieldActionFactory getActionFactory(String component) { + BitFieldActionFactory actionFactory = actionFactories.get(component.toLowerCase()); + if (actionFactory == null) { + throw new RuntimeException("can't get actionFactory for component:" + component); + } + return actionFactory; + } +} 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/persistent/SentryStoreLayer.java ---------------------------------------------------------------------- diff --git a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/generic/service/persistent/SentryStoreLayer.java b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/generic/service/persistent/SentryStoreLayer.java new file mode 100644 index 0000000..ba9e36f --- /dev/null +++ b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/generic/service/persistent/SentryStoreLayer.java @@ -0,0 +1,175 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.sentry.provider.db.generic.service.persistent; + +import java.util.List; +import java.util.Set; + +import org.apache.sentry.SentryUserException; +import org.apache.sentry.core.common.Authorizable; +import org.apache.sentry.provider.db.SentryAlreadyExistsException; +import org.apache.sentry.provider.db.SentryNoSuchObjectException; +import org.apache.sentry.provider.db.service.persistent.CommitContext; + +/** + * Sentry store for persistent the authorize object to database + */ +public interface SentryStoreLayer { + /** + * Create a role + * @param component: The request respond to which component + * @param role: The name of role + * @param requestor: User on whose behalf the request is launched + * @returns commit context used for notification handlers + * @throws SentryAlreadyExistsException + */ + public CommitContext createRole(String component, String role, + String requestor) throws SentryAlreadyExistsException; + + /** + * Drop a role + * @param component: The request respond to which component + * @param role: The name of role + * @param requestor: user on whose behalf the request is launched + * @returns commit context used for notification handlers + * @throws SentryNoSuchObjectException + */ + public CommitContext dropRole(String component, String role, + String requestor) throws SentryNoSuchObjectException; + + /** + * Add a role to groups. + * @param component: The request respond to which component + * @param role: The name of role + * @param groups: The name of groups + * @param requestor: User on whose behalf the request is issued + * @returns commit context used for notification handlers + * @throws SentryNoSuchObjectException + */ + public CommitContext alterRoleAddGroups(String component, String role, + Set<String> groups, String requestor) throws SentryNoSuchObjectException; + + /** + * Delete a role from groups. + * @param component: The request respond to which component + * @param role: The name of role + * @param groups: The name of groups + * @param requestor: User on whose behalf the request is launched + * @returns commit context used for notification handlers + * @throws SentryNoSuchObjectException + */ + public CommitContext alterRoleDeleteGroups(String component, String role, + Set<String> groups, String requestor) throws SentryNoSuchObjectException; + + /** + * Grant a privilege to role. + * @param component: The request respond to which component + * @param role: The name of role + * @param privilege: The privilege object will be granted + * @param grantorPrincipal: User on whose behalf the request is launched + * @returns commit context Used for notification handlers + * @throws SentryUserException + */ + public CommitContext alterRoleGrantPrivilege(String component, String role, + PrivilegeObject privilege, String grantorPrincipal) throws SentryUserException; + + /** + * Revoke a privilege from role. + * @param component: The request respond to which component + * @param role: The name of role + * @param privilege: The privilege object will revoked + * @param grantorPrincipal: User on whose behalf the request is launched + * @returns commit context used for notification handlers + * @throws SentryUserException + */ + public CommitContext alterRoleRevokePrivilege(String component, String role, + PrivilegeObject privilege, String grantorPrincipal) throws SentryUserException; + + /** + * Rename privilege + * + * @param component: The request respond to which component + * @param service: The name of service + * @param oldAuthorizables: The old list of authorize objects + * @param newAuthorizables: The new list of authorize objects + * @param requestor: User on whose behalf the request is launched + * @returns commit context used for notification handlers + * @throws SentryUserException + */ + public CommitContext renamePrivilege( + String component, String service, List<? extends Authorizable> oldAuthorizables, + List<? extends Authorizable> newAuthorizables, String requestor) throws SentryUserException; + + /** + * Drop privilege + * @param component: The request respond to which component + * @param privilege: The privilege will be dropped + * @param requestor: User on whose behalf the request is launched + * @returns commit context used for notification handlers + * @throws SentryUserException + */ + public CommitContext dropPrivilege(String component, PrivilegeObject privilege, + String requestor) throws SentryUserException; + + /** + * Get roles + * @param component: The request respond to which component + * @param groups: The name of groups + * @returns the set of roles + * @throws SentryUserException + */ + public Set<String> getRolesByGroups(String component, Set<String> groups) throws SentryUserException; + + /** + * Get groups + * @param component: The request respond to which component + * @param roles: The name of roles + * @returns the set of groups + * @throws SentryUserException + */ + public Set<String> getGroupsByRoles(String component, Set<String> roles) throws SentryUserException; + + /** + * Get privileges + * @param component: The request respond to which component + * @param roles: The name of roles + * @returns the set of privileges + * @throws SentryUserException + */ + public Set<PrivilegeObject> getPrivilegesByRole(String component, Set<String> roles) throws SentryUserException; + + /** + * get sentry privileges from provider as followings: + * @param component: The request respond to which component + * @param service: The name of service + * @param roles: The name of roles + * @param groups: The name of groups + * @param authorizables: The list of authorize objects + * @returns the set of privileges + * @throws SentryUserException + */ + + public Set<PrivilegeObject> getPrivilegesByProvider(String component, String service,Set<String> roles, + Set<String> groups, List<? extends Authorizable> authorizables) + throws SentryUserException; + /** + * close sentryStore + */ + public void 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/generic/service/thrift/NotificationHandler.java ---------------------------------------------------------------------- diff --git a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/generic/service/thrift/NotificationHandler.java b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/generic/service/thrift/NotificationHandler.java new file mode 100644 index 0000000..d8a51a6 --- /dev/null +++ b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/generic/service/thrift/NotificationHandler.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.generic.service.thrift; + +import org.apache.sentry.provider.db.generic.service.thrift.TAlterSentryRoleAddGroupsRequest; +import org.apache.sentry.provider.db.generic.service.thrift.TAlterSentryRoleAddGroupsResponse; +import org.apache.sentry.provider.db.generic.service.thrift.TAlterSentryRoleDeleteGroupsRequest; +import org.apache.sentry.provider.db.generic.service.thrift.TAlterSentryRoleDeleteGroupsResponse; +import org.apache.sentry.provider.db.generic.service.thrift.TAlterSentryRoleGrantPrivilegeRequest; +import org.apache.sentry.provider.db.generic.service.thrift.TAlterSentryRoleGrantPrivilegeResponse; +import org.apache.sentry.provider.db.generic.service.thrift.TAlterSentryRoleRevokePrivilegeRequest; +import org.apache.sentry.provider.db.generic.service.thrift.TAlterSentryRoleRevokePrivilegeResponse; +import org.apache.sentry.provider.db.generic.service.thrift.TCreateSentryRoleRequest; +import org.apache.sentry.provider.db.generic.service.thrift.TCreateSentryRoleResponse; +import org.apache.sentry.provider.db.generic.service.thrift.TDropPrivilegesRequest; +import org.apache.sentry.provider.db.generic.service.thrift.TDropPrivilegesResponse; +import org.apache.sentry.provider.db.generic.service.thrift.TDropSentryRoleRequest; +import org.apache.sentry.provider.db.generic.service.thrift.TDropSentryRoleResponse; +import org.apache.sentry.provider.db.generic.service.thrift.TRenamePrivilegesRequest; +import org.apache.sentry.provider.db.generic.service.thrift.TRenamePrivilegesResponse; +import org.apache.sentry.provider.db.service.persistent.CommitContext; + +public interface NotificationHandler { + + public void create_sentry_role(CommitContext context, + TCreateSentryRoleRequest request, TCreateSentryRoleResponse response); + + public void drop_sentry_role(CommitContext context, TDropSentryRoleRequest request, + TDropSentryRoleResponse response); + + public void alter_sentry_role_grant_privilege(CommitContext context, TAlterSentryRoleGrantPrivilegeRequest request, + TAlterSentryRoleGrantPrivilegeResponse response); + + public void alter_sentry_role_revoke_privilege(CommitContext context, TAlterSentryRoleRevokePrivilegeRequest request, + TAlterSentryRoleRevokePrivilegeResponse response); + + public void alter_sentry_role_add_groups(CommitContext context,TAlterSentryRoleAddGroupsRequest request, + TAlterSentryRoleAddGroupsResponse response); + + public void alter_sentry_role_delete_groups(CommitContext context, TAlterSentryRoleDeleteGroupsRequest request, + TAlterSentryRoleDeleteGroupsResponse response); + + public void drop_sentry_privilege(CommitContext context, TDropPrivilegesRequest request, + TDropPrivilegesResponse response); + + public void rename_sentry_privilege(CommitContext context, TRenamePrivilegesRequest request, + TRenamePrivilegesResponse response); +} 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/NotificationHandlerInvoker.java ---------------------------------------------------------------------- diff --git a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/generic/service/thrift/NotificationHandlerInvoker.java b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/generic/service/thrift/NotificationHandlerInvoker.java new file mode 100644 index 0000000..317c97b --- /dev/null +++ b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/generic/service/thrift/NotificationHandlerInvoker.java @@ -0,0 +1,180 @@ +/** + * 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.util.List; + +import org.apache.sentry.provider.db.generic.service.thrift.TAlterSentryRoleAddGroupsRequest; +import org.apache.sentry.provider.db.generic.service.thrift.TAlterSentryRoleAddGroupsResponse; +import org.apache.sentry.provider.db.generic.service.thrift.TAlterSentryRoleDeleteGroupsRequest; +import org.apache.sentry.provider.db.generic.service.thrift.TAlterSentryRoleDeleteGroupsResponse; +import org.apache.sentry.provider.db.generic.service.thrift.TAlterSentryRoleGrantPrivilegeRequest; +import org.apache.sentry.provider.db.generic.service.thrift.TAlterSentryRoleGrantPrivilegeResponse; +import org.apache.sentry.provider.db.generic.service.thrift.TAlterSentryRoleRevokePrivilegeRequest; +import org.apache.sentry.provider.db.generic.service.thrift.TAlterSentryRoleRevokePrivilegeResponse; +import org.apache.sentry.provider.db.generic.service.thrift.TCreateSentryRoleRequest; +import org.apache.sentry.provider.db.generic.service.thrift.TCreateSentryRoleResponse; +import org.apache.sentry.provider.db.generic.service.thrift.TDropPrivilegesRequest; +import org.apache.sentry.provider.db.generic.service.thrift.TDropPrivilegesResponse; +import org.apache.sentry.provider.db.generic.service.thrift.TDropSentryRoleRequest; +import org.apache.sentry.provider.db.generic.service.thrift.TDropSentryRoleResponse; +import org.apache.sentry.provider.db.generic.service.thrift.TRenamePrivilegesRequest; +import org.apache.sentry.provider.db.generic.service.thrift.TRenamePrivilegesResponse; +import org.apache.sentry.provider.db.service.persistent.CommitContext; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.collect.Lists; + +/** + * Invokes configured instances of NotificationHandler. Importantly + * NotificationHandler's each receive a copy of the request and + * response thrift objects from each successful request. + */ +public class NotificationHandlerInvoker implements NotificationHandler { + private static final Logger LOGGER = LoggerFactory.getLogger(NotificationHandlerInvoker.class); + List<? extends NotificationHandler> handlers = Lists.newArrayList(); + + public NotificationHandlerInvoker(List<? extends NotificationHandler> handlers) { + this.handlers = handlers; + } + @Override + public void create_sentry_role(CommitContext context, + TCreateSentryRoleRequest request, TCreateSentryRoleResponse response) { + for (NotificationHandler handler : handlers) { + try { + LOGGER.debug("Calling " + handler); + handler.create_sentry_role(context, new TCreateSentryRoleRequest(request), + new TCreateSentryRoleResponse(response)); + } catch (Exception ex) { + LOGGER.error("Unexpected error in " + handler + ". Request: " + + request + ", Response: " + response, ex); + } + } + } + + @Override + public void drop_sentry_role(CommitContext context, + TDropSentryRoleRequest request, TDropSentryRoleResponse response) { + for (NotificationHandler handler : handlers) { + try { + LOGGER.debug("Calling " + handler); + handler.drop_sentry_role(context, new TDropSentryRoleRequest(request), + new TDropSentryRoleResponse(response)); + } catch (Exception ex) { + LOGGER.error("Unexpected error in " + handler + ". Request: " + + request + ", Response: " + response, ex); + } + } + } + + @Override + public void alter_sentry_role_grant_privilege(CommitContext context, + TAlterSentryRoleGrantPrivilegeRequest request, + TAlterSentryRoleGrantPrivilegeResponse response) { + for (NotificationHandler handler : handlers) { + try { + LOGGER.debug("Calling " + handler); + handler.alter_sentry_role_grant_privilege(context, + new TAlterSentryRoleGrantPrivilegeRequest(request), + new TAlterSentryRoleGrantPrivilegeResponse(response)); + } catch (Exception ex) { + LOGGER.error("Unexpected error in " + handler + ". Request: " + + request + ", Response: " + response, ex); + } + } + } + + @Override + public void alter_sentry_role_revoke_privilege(CommitContext context, + TAlterSentryRoleRevokePrivilegeRequest request, + TAlterSentryRoleRevokePrivilegeResponse response) { + for (NotificationHandler handler : handlers) { + try { + LOGGER.debug("Calling " + handler); + handler.alter_sentry_role_revoke_privilege(context, + new TAlterSentryRoleRevokePrivilegeRequest(request), + new TAlterSentryRoleRevokePrivilegeResponse(response)); + } catch (Exception ex) { + LOGGER.error("Unexpected error in " + handler + ". Request: " + + request + ", Response: " + response, ex); + } + } + } + + @Override + public void alter_sentry_role_add_groups(CommitContext context, + TAlterSentryRoleAddGroupsRequest request, + TAlterSentryRoleAddGroupsResponse response) { + for (NotificationHandler handler : handlers) { + try { + LOGGER.debug("Calling " + handler); + handler.alter_sentry_role_add_groups(context, new TAlterSentryRoleAddGroupsRequest(request), + new TAlterSentryRoleAddGroupsResponse(response)); + } catch (Exception ex) { + LOGGER.error("Unexpected error in " + handler + ". Request: " + + request + ", Response: " + response, ex); + } + } + } + + @Override + public void alter_sentry_role_delete_groups(CommitContext context, + TAlterSentryRoleDeleteGroupsRequest request, + TAlterSentryRoleDeleteGroupsResponse response) { + for (NotificationHandler handler : handlers) { + try { + LOGGER.debug("Calling " + handler); + handler.alter_sentry_role_delete_groups(context, new TAlterSentryRoleDeleteGroupsRequest(request), + new TAlterSentryRoleDeleteGroupsResponse(response)); + } catch (Exception ex) { + LOGGER.error("Unexpected error in " + handler + ". Request: " + + request + ", Response: " + response, ex); + } + } + } + @Override + public void drop_sentry_privilege(CommitContext context, + TDropPrivilegesRequest request, TDropPrivilegesResponse response) { + for (NotificationHandler handler : handlers) { + try { + LOGGER.debug("Calling " + handler); + handler.drop_sentry_privilege(context, new TDropPrivilegesRequest(request), + new TDropPrivilegesResponse(response)); + } catch (Exception ex) { + LOGGER.error("Unexpected error in " + handler + ". Request: " + + request + ", Response: " + response, ex); + } + } + } + @Override + public void rename_sentry_privilege(CommitContext context, + TRenamePrivilegesRequest request, TRenamePrivilegesResponse response) { + for (NotificationHandler handler : handlers) { + try { + LOGGER.debug("Calling " + handler); + handler.rename_sentry_privilege(context, new TRenamePrivilegesRequest(request), + new TRenamePrivilegesResponse(response)); + } catch (Exception ex) { + LOGGER.error("Unexpected error in " + handler + ". Request: " + + request + ", Response: " + response, ex); + } + } + } + +}