You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sentry.apache.org by as...@apache.org on 2014/12/19 06:09:41 UTC
[04/13] incubator-sentry git commit: SENTRY-398: Generic
authorization model for Sentry (shenguoquan via Arun Suresh)
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);
+ }
+ }
+ }
+
+}