http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/217e1892/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerMutableResource.java ---------------------------------------------------------------------- diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerMutableResource.java b/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerMutableResource.java new file mode 100644 index 0000000..f49bf8c --- /dev/null +++ b/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerMutableResource.java @@ -0,0 +1,27 @@ +/* + * 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.ranger.plugin.policyengine; + + +public interface RangerMutableResource extends RangerResource { + void setOwnerUser(String ownerUser); + + void setValue(String type, String value); +}
http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/217e1892/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerPolicyEngine.java ---------------------------------------------------------------------- diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerPolicyEngine.java b/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerPolicyEngine.java new file mode 100644 index 0000000..a66bc23 --- /dev/null +++ b/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerPolicyEngine.java @@ -0,0 +1,54 @@ +/* + * 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.ranger.plugin.policyengine; + +import java.util.Collection; +import java.util.List; + +import org.apache.ranger.plugin.audit.RangerAuditHandler; +import org.apache.ranger.plugin.model.RangerPolicy; +import org.apache.ranger.plugin.model.RangerServiceDef; + +public interface RangerPolicyEngine { + public static final String GROUP_PUBLIC = "public"; + public static final String ANY_ACCESS = "_any"; + public static final String ADMIN_ACCESS = "_admin"; + public static final long UNKNOWN_POLICY = -1; + + String getServiceName(); + + RangerServiceDef getServiceDef(); + + void setPolicies(String serviceName, RangerServiceDef serviceDef, List<RangerPolicy> policies); + + void setDefaultAuditHandler(RangerAuditHandler auditHandler); + + RangerAuditHandler getDefaultAuditHandler(); + + RangerAccessResult createAccessResult(RangerAccessRequest request); + + RangerAccessResult isAccessAllowed(RangerAccessRequest request); + + Collection<RangerAccessResult> isAccessAllowed(Collection<RangerAccessRequest> requests); + + RangerAccessResult isAccessAllowed(RangerAccessRequest request, RangerAuditHandler auditHandler); + + Collection<RangerAccessResult> isAccessAllowed(Collection<RangerAccessRequest> requests, RangerAuditHandler auditHandler); +} http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/217e1892/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerPolicyEngineImpl.java ---------------------------------------------------------------------- diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerPolicyEngineImpl.java b/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerPolicyEngineImpl.java new file mode 100644 index 0000000..8f6231b --- /dev/null +++ b/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerPolicyEngineImpl.java @@ -0,0 +1,254 @@ +/* + * 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.ranger.plugin.policyengine; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.ranger.plugin.audit.RangerAuditHandler; +import org.apache.ranger.plugin.model.RangerPolicy; +import org.apache.ranger.plugin.model.RangerServiceDef; +import org.apache.ranger.plugin.policyevaluator.RangerDefaultPolicyEvaluator; +import org.apache.ranger.plugin.policyevaluator.RangerPolicyEvaluator; + + +public class RangerPolicyEngineImpl implements RangerPolicyEngine { + private static final Log LOG = LogFactory.getLog(RangerPolicyEngineImpl.class); + + private String serviceName = null; + private RangerServiceDef serviceDef = null; + private List<RangerPolicyEvaluator> policyEvaluators = null; + private RangerAuditHandler defaultAuditHandler = null; + + + public RangerPolicyEngineImpl() { + if(LOG.isDebugEnabled()) { + LOG.debug("==> RangerPolicyEngineImpl()"); + } + + if(LOG.isDebugEnabled()) { + LOG.debug("<== RangerPolicyEngineImpl()"); + } + } + + @Override + public String getServiceName() { + return serviceName; + } + + @Override + public RangerServiceDef getServiceDef() { + return serviceDef; + } + + @Override + public void setPolicies(String serviceName, RangerServiceDef serviceDef, List<RangerPolicy> policies) { + if(LOG.isDebugEnabled()) { + LOG.debug("==> RangerPolicyEngineImpl.setPolicies(" + serviceName + ", " + serviceDef + ", policies.count=" + (policies == null ? 0 : policies.size()) + ")"); + } + + if(serviceName != null && serviceDef != null && policies != null) { + List<RangerPolicyEvaluator> evaluators = new ArrayList<RangerPolicyEvaluator>(); + + for(RangerPolicy policy : policies) { + if(! policy.getIsEnabled()) { + continue; + } + + RangerPolicyEvaluator evaluator = getPolicyEvaluator(policy, serviceDef); + + if(evaluator != null) { + evaluators.add(evaluator); + } + } + + /* TODO: + * sort evaluators list for faster completion of isAccessAllowed() method + * 1. Global policies: the policies that cover for any resource (for example: database=*; table=*; column=*) + * 2. Policies that cover all resources under level-1 (for example: every thing in one or more databases) + * 3. Policies that cover all resources under level-2 (for example: every thing in one or more tables) + * ... + * 4. Policies that cover all resources under level-n (for example: one or more columns) + * + */ + + this.serviceName = serviceName; + this.serviceDef = serviceDef; + this.policyEvaluators = evaluators; + } else { + LOG.error("RangerPolicyEngineImpl.setPolicies(): invalid arguments - null serviceDef/policies"); + } + + if(LOG.isDebugEnabled()) { + LOG.debug("<== RangerPolicyEngineImpl.setPolicies(" + serviceName + ", " + serviceDef + ", policies.count=" + (policies == null ? 0 : policies.size()) + ")"); + } + } + + @Override + public void setDefaultAuditHandler(RangerAuditHandler auditHandler) { + this.defaultAuditHandler = auditHandler; + } + + @Override + public RangerAuditHandler getDefaultAuditHandler() { + return defaultAuditHandler; + } + + @Override + public RangerAccessResult createAccessResult(RangerAccessRequest request) { + return new RangerAccessResult(serviceName, serviceDef, request); + } + + @Override + public RangerAccessResult isAccessAllowed(RangerAccessRequest request) { + return isAccessAllowed(request, defaultAuditHandler); + } + + @Override + public Collection<RangerAccessResult> isAccessAllowed(Collection<RangerAccessRequest> requests) { + return isAccessAllowed(requests, defaultAuditHandler); + } + + @Override + public RangerAccessResult isAccessAllowed(RangerAccessRequest request, RangerAuditHandler auditHandler) { + if(LOG.isDebugEnabled()) { + LOG.debug("==> RangerPolicyEngineImpl.isAccessAllowed(" + request + ")"); + } + + RangerAccessResult ret = isAccessAllowedNoAudit(request); + + if(auditHandler != null) { + auditHandler.logAudit(ret); + } + + if(LOG.isDebugEnabled()) { + LOG.debug("<== RangerPolicyEngineImpl.isAccessAllowed(" + request + "): " + ret); + } + + return ret; + } + + @Override + public Collection<RangerAccessResult> isAccessAllowed(Collection<RangerAccessRequest> requests, RangerAuditHandler auditHandler) { + if(LOG.isDebugEnabled()) { + LOG.debug("==> RangerPolicyEngineImpl.isAccessAllowed(" + requests + ")"); + } + + Collection<RangerAccessResult> ret = new ArrayList<RangerAccessResult>(); + + if(requests != null) { + for(RangerAccessRequest request : requests) { + RangerAccessResult result = isAccessAllowedNoAudit(request); + + ret.add(result); + } + } + + if(auditHandler != null) { + auditHandler.logAudit(ret); + } + + if(LOG.isDebugEnabled()) { + LOG.debug("<== RangerPolicyEngineImpl.isAccessAllowed(" + requests + "): " + ret); + } + + return ret; + } + + protected RangerAccessResult isAccessAllowedNoAudit(RangerAccessRequest request) { + if(LOG.isDebugEnabled()) { + LOG.debug("==> RangerPolicyEngineImpl.isAccessAllowedNoAudit(" + request + ")"); + } + + RangerAccessResult ret = createAccessResult(request); + + if(request != null) { + List<RangerPolicyEvaluator> evaluators = policyEvaluators; + + if(evaluators != null) { + for(RangerPolicyEvaluator evaluator : evaluators) { + evaluator.evaluate(request, ret); + + // stop once allowed=true && audited==true + if(ret.getIsAllowed() && ret.getIsAudited()) { + break; + } + } + } + } + + if(LOG.isDebugEnabled()) { + LOG.debug("<== RangerPolicyEngineImpl.isAccessAllowedNoAudit(" + request + "): " + ret); + } + + return ret; + } + + private RangerPolicyEvaluator getPolicyEvaluator(RangerPolicy policy, RangerServiceDef serviceDef) { + if(LOG.isDebugEnabled()) { + LOG.debug("==> RangerPolicyEngineImpl.getPolicyEvaluator(" + policy + "," + serviceDef + ")"); + } + + RangerPolicyEvaluator ret = null; + + ret = new RangerDefaultPolicyEvaluator(); // TODO: configurable evaluator class? + + ret.init(policy, serviceDef); + + if(LOG.isDebugEnabled()) { + LOG.debug("<== RangerPolicyEngineImpl.getPolicyEvaluator(" + policy + "," + serviceDef + "): " + ret); + } + + return ret; + } + + @Override + public String toString( ) { + StringBuilder sb = new StringBuilder(); + + toString(sb); + + return sb.toString(); + } + + public StringBuilder toString(StringBuilder sb) { + sb.append("RangerPolicyEngineImpl={"); + + sb.append("serviceName={").append(serviceName).append("} "); + sb.append("serviceDef={").append(serviceDef).append("} "); + + sb.append("policyEvaluators={"); + if(policyEvaluators != null) { + for(RangerPolicyEvaluator policyEvaluator : policyEvaluators) { + if(policyEvaluator != null) { + sb.append(policyEvaluator).append(" "); + } + } + } + sb.append("} "); + + sb.append("}"); + + return sb; + } +} http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/217e1892/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerResource.java ---------------------------------------------------------------------- diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerResource.java b/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerResource.java new file mode 100644 index 0000000..6941bc3 --- /dev/null +++ b/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerResource.java @@ -0,0 +1,33 @@ +/* + * 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.ranger.plugin.policyengine; + +import java.util.Set; + + +public interface RangerResource { + public abstract String getOwnerUser(); + + public abstract boolean exists(String name); + + public abstract String getValue(String name); + + public Set<String> getKeys(); +} http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/217e1892/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerResourceImpl.java ---------------------------------------------------------------------- diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerResourceImpl.java b/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerResourceImpl.java new file mode 100644 index 0000000..86f7ea4 --- /dev/null +++ b/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/RangerResourceImpl.java @@ -0,0 +1,107 @@ +/* + * 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.ranger.plugin.policyengine; + +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + + +public class RangerResourceImpl implements RangerMutableResource { + private String ownerUser = null; + private Map<String, String> elements = null; + + + public RangerResourceImpl() { + } + + @Override + public String getOwnerUser() { + return ownerUser; + } + + @Override + public boolean exists(String name) { + return elements != null && elements.containsKey(name); + } + + @Override + public String getValue(String name) { + String ret = null; + + if(elements != null && elements.containsKey(name)) { + ret = elements.get(name); + } + + return ret; + } + + @Override + public Set<String> getKeys() { + Set<String> ret = null; + + if(elements != null) { + ret = elements.keySet(); + } + + return ret; + } + + @Override + public void setOwnerUser(String ownerUser) { + this.ownerUser = ownerUser; + } + + @Override + public void setValue(String name, String value) { + if(elements == null) { + elements = new HashMap<String, String>(); + } + + elements.put(name, value); + } + + @Override + public String toString( ) { + StringBuilder sb = new StringBuilder(); + + toString(sb); + + return sb.toString(); + } + + public StringBuilder toString(StringBuilder sb) { + sb.append("RangerResourceImpl={"); + + sb.append("ownerUser={").append(ownerUser).append("} "); + + sb.append("elements={"); + if(elements != null) { + for(Map.Entry<String, String> e : elements.entrySet()) { + sb.append(e.getKey()).append("=").append(e.getValue()).append("; "); + } + } + sb.append("} "); + + sb.append("}"); + + return sb; + } +} http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/217e1892/agents-common/src/main/java/org/apache/ranger/plugin/policyevaluator/RangerAbstractPolicyEvaluator.java ---------------------------------------------------------------------- diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/policyevaluator/RangerAbstractPolicyEvaluator.java b/agents-common/src/main/java/org/apache/ranger/plugin/policyevaluator/RangerAbstractPolicyEvaluator.java new file mode 100644 index 0000000..36273eb --- /dev/null +++ b/agents-common/src/main/java/org/apache/ranger/plugin/policyevaluator/RangerAbstractPolicyEvaluator.java @@ -0,0 +1,79 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.ranger.plugin.policyevaluator; + + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.ranger.plugin.model.RangerPolicy; +import org.apache.ranger.plugin.model.RangerServiceDef; + + +public abstract class RangerAbstractPolicyEvaluator implements RangerPolicyEvaluator { + private static final Log LOG = LogFactory.getLog(RangerAbstractPolicyEvaluator.class); + + private RangerPolicy policy = null; + private RangerServiceDef serviceDef = null; + + + @Override + public void init(RangerPolicy policy, RangerServiceDef serviceDef) { + if(LOG.isDebugEnabled()) { + LOG.debug("==> RangerAbstractPolicyEvaluator.init(" + policy + ", " + serviceDef + ")"); + } + + this.policy = policy; + this.serviceDef = serviceDef; + + if(LOG.isDebugEnabled()) { + LOG.debug("<== RangerAbstractPolicyEvaluator.init(" + policy + ", " + serviceDef + ")"); + } + } + + @Override + public RangerPolicy getPolicy() { + return policy; + } + + @Override + public RangerServiceDef getServiceDef() { + return serviceDef; + } + + @Override + public String toString( ) { + StringBuilder sb = new StringBuilder(); + + toString(sb); + + return sb.toString(); + } + + public StringBuilder toString(StringBuilder sb) { + sb.append("RangerAbstractPolicyEvaluator={"); + + sb.append("policy={").append(policy).append("} "); + sb.append("serviceDef={").append(serviceDef).append("} "); + + sb.append("}"); + + return sb; + } +} http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/217e1892/agents-common/src/main/java/org/apache/ranger/plugin/policyevaluator/RangerDefaultPolicyEvaluator.java ---------------------------------------------------------------------- diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/policyevaluator/RangerDefaultPolicyEvaluator.java b/agents-common/src/main/java/org/apache/ranger/plugin/policyevaluator/RangerDefaultPolicyEvaluator.java new file mode 100644 index 0000000..cc1ee1e --- /dev/null +++ b/agents-common/src/main/java/org/apache/ranger/plugin/policyevaluator/RangerDefaultPolicyEvaluator.java @@ -0,0 +1,446 @@ +/* + * 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.ranger.plugin.policyevaluator; + +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; + +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.lang.StringUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.ranger.plugin.model.RangerPolicy; +import org.apache.ranger.plugin.model.RangerServiceDef; +import org.apache.ranger.plugin.model.RangerPolicy.RangerPolicyItem; +import org.apache.ranger.plugin.model.RangerPolicy.RangerPolicyItemAccess; +import org.apache.ranger.plugin.model.RangerPolicy.RangerPolicyResource; +import org.apache.ranger.plugin.model.RangerServiceDef.RangerAccessTypeDef; +import org.apache.ranger.plugin.model.RangerServiceDef.RangerResourceDef; +import org.apache.ranger.plugin.policyengine.RangerAccessRequest; +import org.apache.ranger.plugin.policyengine.RangerAccessResult; +import org.apache.ranger.plugin.policyengine.RangerPolicyEngine; +import org.apache.ranger.plugin.policyengine.RangerResource; +import org.apache.ranger.plugin.resourcematcher.RangerDefaultResourceMatcher; +import org.apache.ranger.plugin.resourcematcher.RangerResourceMatcher; + + +public class RangerDefaultPolicyEvaluator extends RangerAbstractPolicyEvaluator { + private static final Log LOG = LogFactory.getLog(RangerDefaultPolicyEvaluator.class); + + private Map<String, RangerResourceMatcher> matchers = null; + + @Override + public void init(RangerPolicy policy, RangerServiceDef serviceDef) { + if(LOG.isDebugEnabled()) { + LOG.debug("==> RangerDefaultPolicyEvaluator.init()"); + } + + preprocessPolicy(policy, serviceDef); + + super.init(policy, serviceDef); + + this.matchers = new HashMap<String, RangerResourceMatcher>(); + + if(policy != null && policy.getResources() != null && serviceDef != null) { + for(RangerResourceDef resourceDef : serviceDef.getResources()) { + String resourceName = resourceDef.getName(); + RangerPolicyResource policyResource = policy.getResources().get(resourceName); + + RangerResourceMatcher matcher = createResourceMatcher(resourceDef, policyResource); + + if(matcher != null) { + matchers.put(resourceName, matcher); + } else { + LOG.error("failed to find matcher for resource " + resourceName); + } + } + } + + if(LOG.isDebugEnabled()) { + LOG.debug("<== RangerDefaultPolicyEvaluator.init()"); + } + } + + @Override + public void evaluate(RangerAccessRequest request, RangerAccessResult result) { + if(LOG.isDebugEnabled()) { + LOG.debug("==> RangerDefaultPolicyEvaluator.evaluate(" + request + ", " + result + ")"); + } + + RangerPolicy policy = getPolicy(); + + if(policy != null && request != null && result != null) { + boolean isResourceMatch = matchResource(request.getResource()); + boolean isResourceHeadMatch = isResourceMatch || matchResourceHead(request.getResource()); + String accessType = request.getAccessType(); + + if(StringUtils.isEmpty(accessType)) { + accessType = RangerPolicyEngine.ANY_ACCESS; + } + + boolean isAnyAccess = StringUtils.equals(accessType, RangerPolicyEngine.ANY_ACCESS); + + if(isResourceMatch || (isResourceHeadMatch && isAnyAccess)) { + if(policy.getIsAuditEnabled()) { + result.setIsAudited(true); + } + + for(RangerPolicyItem policyItem : policy.getPolicyItems()) { + if(result.getIsAllowed()) { + break; + } + + if(CollectionUtils.isEmpty(policyItem.getAccesses())) { + continue; + } + + boolean isUserGroupMatch = matchUserGroup(policyItem, request.getUser(), request.getUserGroups()); + + if(! isUserGroupMatch) { + continue; + } + + boolean isCustomConditionsMatch = matchCustomConditions(policyItem, request); + + if(! isCustomConditionsMatch) { + continue; + } + + if(isAnyAccess) { + for(RangerPolicyItemAccess access : policyItem.getAccesses()) { + if(access.getIsAllowed()) { + result.setIsAllowed(true); + result.setPolicyId(policy.getId()); + break; + } + } + } else { + RangerPolicyItemAccess access = getAccess(policyItem, accessType); + + if(access != null && access.getIsAllowed()) { + result.setIsAllowed(true); + result.setPolicyId(policy.getId()); + } + } + } + } + } + + if(LOG.isDebugEnabled()) { + LOG.debug("<== RangerDefaultPolicyEvaluator.evaluate(" + request + ", " + result + ")"); + } + } + + protected boolean matchResource(RangerResource resource) { + if(LOG.isDebugEnabled()) { + LOG.debug("==> RangerDefaultPolicyEvaluator.matchResource(" + resource + ")"); + } + + boolean ret = false; + + RangerServiceDef serviceDef = getServiceDef(); + + if(serviceDef != null && serviceDef.getResources() != null) { + Collection<String> resourceKeys = resource == null ? null : resource.getKeys(); + Collection<String> policyKeys = matchers == null ? null : matchers.keySet(); + + boolean keysMatch = (resourceKeys == null) || (policyKeys != null && policyKeys.containsAll(resourceKeys)); + + if(keysMatch) { + for(RangerResourceDef resourceDef : serviceDef.getResources()) { + String resourceName = resourceDef.getName(); + String resourceValue = resource == null ? null : resource.getValue(resourceName); + RangerResourceMatcher matcher = matchers == null ? null : matchers.get(resourceName); + + // when no value exists for a resourceName, consider it a match only if (policy doesn't have a matcher OR matcher allows no-value resource) + if(StringUtils.isEmpty(resourceValue)) { + ret = matcher == null || matcher.isMatch(resourceValue); + } else { + ret = matcher != null && matcher.isMatch(resourceValue); + } + + if(! ret) { + break; + } + } + } + } + + if(LOG.isDebugEnabled()) { + LOG.debug("<== RangerDefaultPolicyEvaluator.matchResource(" + resource + "): " + ret); + } + + return ret; + } + + protected boolean matchResourceHead(RangerResource resource) { + if(LOG.isDebugEnabled()) { + LOG.debug("==> RangerDefaultPolicyEvaluator.matchResourceHead(" + resource + ")"); + } + + boolean ret = false; + + RangerServiceDef serviceDef = getServiceDef(); + + if(serviceDef != null && serviceDef.getResources() != null) { + int numMatched = 0; + int numUnmatched = 0; + + for(RangerResourceDef resourceDef : serviceDef.getResources()) { + String resourceName = resourceDef.getName(); + String resourceValue = resource == null ? null : resource.getValue(resourceName); + RangerResourceMatcher matcher = matchers == null ? null : matchers.get(resourceName); + + if(numUnmatched > 0) { // no further values are expected in the resource + if(! StringUtils.isEmpty(resourceValue)) { + break; + } + + numUnmatched++; + continue; + } else { + boolean isMatch = false; + + // when no value exists for a resourceName, consider it a match only if (policy doesn't have a matcher OR matcher allows no-value resource) + if(StringUtils.isEmpty(resourceValue)) { + isMatch = matcher == null || matcher.isMatch(resourceValue); + } else { + isMatch = matcher != null && matcher.isMatch(resourceValue); + } + + if(isMatch) { + numMatched++; + } else { + numUnmatched++; + } + } + } + + ret = (numMatched > 0) && serviceDef.getResources().size() == (numMatched + numUnmatched); + } + + if(LOG.isDebugEnabled()) { + LOG.debug("<== RangerDefaultPolicyEvaluator.matchResourceHead(" + resource + "): " + ret); + } + + return ret; + } + + protected boolean matchUserGroup(RangerPolicyItem policyItem, String user, Collection<String> groups) { + if(LOG.isDebugEnabled()) { + LOG.debug("==> RangerDefaultPolicyEvaluator.matchUserGroup(" + policyItem + ", " + user + ", " + groups + ")"); + } + + boolean ret = false; + + if(policyItem != null) { + if(!ret && user != null && policyItem.getUsers() != null) { + ret = policyItem.getUsers().contains(user); + } + + if(!ret && groups != null && policyItem.getGroups() != null) { + ret = policyItem.getGroups().contains(RangerPolicyEngine.GROUP_PUBLIC) || + !Collections.disjoint(policyItem.getGroups(), groups); + } + } + + if(LOG.isDebugEnabled()) { + LOG.debug("<== RangerDefaultPolicyEvaluator.matchUserGroup(" + policyItem + ", " + user + ", " + groups + "): " + ret); + } + + return ret; + } + + protected boolean matchCustomConditions(RangerPolicyItem policyItem, RangerAccessRequest request) { + if(LOG.isDebugEnabled()) { + LOG.debug("==> RangerDefaultPolicyEvaluator.matchCustomConditions(" + policyItem + ", " + request + ")"); + } + + boolean ret = false; + + // TODO: + ret = true; + + if(LOG.isDebugEnabled()) { + LOG.debug("<== RangerDefaultPolicyEvaluator.matchCustomConditions(" + policyItem + ", " + request + "): " + ret); + } + + return ret; + } + + protected RangerPolicyItemAccess getAccess(RangerPolicyItem policyItem, String accessType) { + if(LOG.isDebugEnabled()) { + LOG.debug("==> RangerDefaultPolicyEvaluator.getAccess(" + policyItem + ", " + accessType + ")"); + } + + RangerPolicyItemAccess ret = null; + + if(policyItem != null && accessType != null && policyItem.getAccesses() != null) { + for(RangerPolicyItemAccess access : policyItem.getAccesses()) { + if(StringUtils.equalsIgnoreCase(accessType, access.getType())) { + ret = access; + + break; + } + } + } + + if(LOG.isDebugEnabled()) { + LOG.debug("<== RangerDefaultPolicyEvaluator.getAccess(" + policyItem + ", " + accessType + "): " + ret); + } + + return ret; + } + + protected RangerResourceMatcher createResourceMatcher(RangerResourceDef resourceDef, RangerPolicyResource resource) { + if(LOG.isDebugEnabled()) { + LOG.debug("==> RangerDefaultPolicyEvaluator.createResourceMatcher(" + resourceDef + ", " + resource + ")"); + } + + RangerResourceMatcher ret = null; + + String clsName = resourceDef != null ? resourceDef.getMatcher() : null; + String options = resourceDef != null ? resourceDef.getMatcherOptions() : null; + + if(StringUtils.isEmpty(clsName)) { + ret = new RangerDefaultResourceMatcher(); + } else { + try { + @SuppressWarnings("unchecked") + Class<RangerResourceMatcher> matcherClass = (Class<RangerResourceMatcher>)Class.forName(clsName); + + ret = matcherClass.newInstance(); + } catch(ClassNotFoundException excp) { + // TODO: ERROR + excp.printStackTrace(); + } catch (InstantiationException excp) { + // TODO: ERROR + excp.printStackTrace(); + } catch (IllegalAccessException excp) { + // TODO: ERROR + excp.printStackTrace(); + } + } + + if(ret != null) { + ret.init(resourceDef, resource, options); + } + + if(LOG.isDebugEnabled()) { + LOG.debug("==> RangerDefaultPolicyEvaluator.createResourceMatcher(" + resourceDef + ", " + resource + "): " + ret); + } + + return ret; + } + + public StringBuilder toString(StringBuilder sb) { + sb.append("RangerDefaultPolicyEvaluator={"); + + super.toString(sb); + + sb.append("matchers={"); + if(matchers != null) { + for(RangerResourceMatcher matcher : matchers.values()) { + sb.append("{").append(matcher).append("} "); + } + } + sb.append("} "); + + sb.append("}"); + + return sb; + } + + private void preprocessPolicy(RangerPolicy policy, RangerServiceDef serviceDef) { + if(policy == null || CollectionUtils.isEmpty(policy.getPolicyItems()) || serviceDef == null) { + return; + } + + Map<String, Collection<String>> impliedAccessGrants = getImpliedAccessGrants(serviceDef); + + if(impliedAccessGrants == null || impliedAccessGrants.isEmpty()) { + return; + } + + for(RangerPolicyItem policyItem : policy.getPolicyItems()) { + if(CollectionUtils.isEmpty(policyItem.getAccesses())) { + continue; + } + + // Only one round of 'expansion' is done; multi-level impliedGrants (like shown below) are not handled for now + // multi-level impliedGrants: given admin=>write; write=>read: must imply admin=>read,write + for(Map.Entry<String, Collection<String>> e : impliedAccessGrants.entrySet()) { + String accessType = e.getKey(); + Collection<String> impliedGrants = e.getValue(); + + RangerPolicyItemAccess access = getAccess(policyItem, accessType); + + if(access == null) { + continue; + } + + for(String impliedGrant : impliedGrants) { + RangerPolicyItemAccess impliedAccess = getAccess(policyItem, impliedGrant); + + if(impliedAccess == null) { + impliedAccess = new RangerPolicyItemAccess(impliedGrant, access.getIsAllowed()); + + policyItem.getAccesses().add(impliedAccess); + } else { + if(! impliedAccess.getIsAllowed()) { + impliedAccess.setIsAllowed(access.getIsAllowed()); + } + } + } + } + } + } + + private Map<String, Collection<String>> getImpliedAccessGrants(RangerServiceDef serviceDef) { + Map<String, Collection<String>> ret = null; + + if(serviceDef != null && !CollectionUtils.isEmpty(serviceDef.getAccessTypes())) { + for(RangerAccessTypeDef accessTypeDef : serviceDef.getAccessTypes()) { + if(!CollectionUtils.isEmpty(accessTypeDef.getImpliedGrants())) { + if(ret == null) { + ret = new HashMap<String, Collection<String>>(); + } + + Collection<String> impliedAccessGrants = ret.get(accessTypeDef.getName()); + + if(impliedAccessGrants == null) { + impliedAccessGrants = new HashSet<String>(); + + ret.put(accessTypeDef.getName(), impliedAccessGrants); + } + + for(String impliedAccessGrant : accessTypeDef.getImpliedGrants()) { + impliedAccessGrants.add(impliedAccessGrant); + } + } + } + } + + return ret; + } +} http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/217e1892/agents-common/src/main/java/org/apache/ranger/plugin/policyevaluator/RangerPolicyEvaluator.java ---------------------------------------------------------------------- diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/policyevaluator/RangerPolicyEvaluator.java b/agents-common/src/main/java/org/apache/ranger/plugin/policyevaluator/RangerPolicyEvaluator.java new file mode 100644 index 0000000..b6e0f10 --- /dev/null +++ b/agents-common/src/main/java/org/apache/ranger/plugin/policyevaluator/RangerPolicyEvaluator.java @@ -0,0 +1,35 @@ +/* + * 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.ranger.plugin.policyevaluator; + +import org.apache.ranger.plugin.model.RangerPolicy; +import org.apache.ranger.plugin.model.RangerServiceDef; +import org.apache.ranger.plugin.policyengine.RangerAccessRequest; +import org.apache.ranger.plugin.policyengine.RangerAccessResult; + +public interface RangerPolicyEvaluator { + void init(RangerPolicy policy, RangerServiceDef serviceDef); + + RangerPolicy getPolicy(); + + RangerServiceDef getServiceDef(); + + void evaluate(RangerAccessRequest request, RangerAccessResult result); +} http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/217e1892/agents-common/src/main/java/org/apache/ranger/plugin/resourcematcher/RangerAbstractResourceMatcher.java ---------------------------------------------------------------------- diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/resourcematcher/RangerAbstractResourceMatcher.java b/agents-common/src/main/java/org/apache/ranger/plugin/resourcematcher/RangerAbstractResourceMatcher.java new file mode 100644 index 0000000..9fb248a --- /dev/null +++ b/agents-common/src/main/java/org/apache/ranger/plugin/resourcematcher/RangerAbstractResourceMatcher.java @@ -0,0 +1,226 @@ +/* + * 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.ranger.plugin.resourcematcher; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.commons.lang.StringUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.ranger.plugin.model.RangerPolicy.RangerPolicyResource; +import org.apache.ranger.plugin.model.RangerServiceDef.RangerResourceDef; + + +public abstract class RangerAbstractResourceMatcher implements RangerResourceMatcher { + private static final Log LOG = LogFactory.getLog(RangerAbstractResourceMatcher.class); + + public final String WILDCARD_PATTERN = ".*"; + + public final String OPTIONS_SEP = ";"; + public final String OPTION_NV_SEP = "="; + public final String OPTION_IGNORE_CASE = "ignoreCase"; + public final String OPTION_WILD_CARD = "wildCard"; + + private RangerResourceDef resourceDef = null; + private RangerPolicyResource policyResource = null; + private String optionsString = null; + private Map<String, String> options = null; + + protected boolean optIgnoreCase = false; + protected boolean optWildCard = false; + + protected List<String> policyValues = null; + protected boolean policyIsExcludes = false; + protected boolean isMatchAny = false; + + @Override + public void init(RangerResourceDef resourceDef, RangerPolicyResource policyResource, String optionsString) { + if(LOG.isDebugEnabled()) { + LOG.debug("==> RangerAbstractResourceMatcher.init(" + resourceDef + ", " + policyResource + ", " + optionsString + ")"); + } + + this.resourceDef = resourceDef; + this.policyResource = policyResource; + this.optionsString = optionsString; + + options = new HashMap<String, String>(); + + if(optionsString != null) { + for(String optionString : optionsString.split(OPTIONS_SEP)) { + if(StringUtils.isEmpty(optionString)) { + continue; + } + + String[] nvArr = optionString.split(OPTION_NV_SEP); + + String name = (nvArr != null && nvArr.length > 0) ? nvArr[0].trim() : null; + String value = (nvArr != null && nvArr.length > 1) ? nvArr[1].trim() : null; + + if(StringUtils.isEmpty(name)) { + continue; + } + + options.put(name, value); + } + } + + optIgnoreCase = getBooleanOption(OPTION_IGNORE_CASE, true); + optWildCard = getBooleanOption(OPTION_WILD_CARD, true); + + policyValues = new ArrayList<String>(); + policyIsExcludes = policyResource == null ? false : policyResource.getIsExcludes(); + + if(policyResource != null && policyResource.getValues() != null) { + for(String policyValue : policyResource.getValues()) { + if(StringUtils.isEmpty(policyValue)) { + continue; + } + + if(optIgnoreCase) { + policyValue = policyValue.toLowerCase(); + } + + if(optWildCard) { + policyValue = getWildCardPattern(policyValue); + } + + if(policyValue.equals(WILDCARD_PATTERN)) { + isMatchAny = true; + } + + policyValues.add(policyValue); + } + } + + if(policyValues.isEmpty()) { + isMatchAny = true; + } + + if(LOG.isDebugEnabled()) { + LOG.debug("<== RangerAbstractResourceMatcher.init(" + resourceDef + ", " + policyResource + ", " + optionsString + ")"); + } + } + + @Override + public RangerResourceDef getResourceDef() { + return resourceDef; + } + + @Override + public RangerPolicyResource getPolicyResource() { + return policyResource; + } + + @Override + public String getOptionsString() { + return optionsString; + } + + + public String getOption(String name) { + String ret = null; + + if(options != null && name != null) { + ret = options.get(name); + } + + return ret; + } + + public String getOption(String name, String defaultValue) { + String ret = getOption(name); + + if(StringUtils.isEmpty(ret)) { + ret = defaultValue; + } + + return ret; + } + + public boolean getBooleanOption(String name) { + String val = getOption(name); + + boolean ret = StringUtils.isEmpty(val) ? false : Boolean.parseBoolean(val); + + return ret; + } + + public boolean getBooleanOption(String name, boolean defaultValue) { + String strVal = getOption(name); + + boolean ret = StringUtils.isEmpty(strVal) ? defaultValue : Boolean.parseBoolean(strVal); + + return ret; + } + + public String getWildCardPattern(String policyValue) { + if (policyValue != null) { + policyValue = policyValue.replaceAll("\\?", "\\.") + .replaceAll("\\*", ".*") ; + } + + return policyValue ; + } + + @Override + public String toString( ) { + StringBuilder sb = new StringBuilder(); + + toString(sb); + + return sb.toString(); + } + + public StringBuilder toString(StringBuilder sb) { + sb.append("RangerAbstractResourceMatcher={"); + + sb.append("resourceDef={"); + if(resourceDef != null) { + resourceDef.toString(sb); + } + sb.append("} "); + sb.append("policyResource={"); + if(policyResource != null) { + policyResource.toString(sb); + } + sb.append("} "); + sb.append("optionsString={").append(optionsString).append("} "); + sb.append("optIgnoreCase={").append(optIgnoreCase).append("} "); + sb.append("optWildCard={").append(optWildCard).append("} "); + sb.append("policyValues={").append(StringUtils.join(policyValues, ",")).append("} "); + sb.append("policyIsExcludes={").append(policyIsExcludes).append("} "); + sb.append("isMatchAny={").append(isMatchAny).append("} "); + + sb.append("options={"); + if(options != null) { + for(Map.Entry<String, String> e : options.entrySet()) { + sb.append(e.getKey()).append("=").append(e.getValue()).append(OPTIONS_SEP); + } + } + sb.append("} "); + + sb.append("}"); + + return sb; + } +} http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/217e1892/agents-common/src/main/java/org/apache/ranger/plugin/resourcematcher/RangerDefaultResourceMatcher.java ---------------------------------------------------------------------- diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/resourcematcher/RangerDefaultResourceMatcher.java b/agents-common/src/main/java/org/apache/ranger/plugin/resourcematcher/RangerDefaultResourceMatcher.java new file mode 100644 index 0000000..13500dc --- /dev/null +++ b/agents-common/src/main/java/org/apache/ranger/plugin/resourcematcher/RangerDefaultResourceMatcher.java @@ -0,0 +1,101 @@ +/* + * 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.ranger.plugin.resourcematcher; + + +import org.apache.commons.lang.StringUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.ranger.plugin.model.RangerPolicy.RangerPolicyResource; +import org.apache.ranger.plugin.model.RangerServiceDef.RangerResourceDef; + + +public class RangerDefaultResourceMatcher extends RangerAbstractResourceMatcher { + private static final Log LOG = LogFactory.getLog(RangerDefaultResourceMatcher.class); + + + @Override + public void init(RangerResourceDef resourceDef, RangerPolicyResource policyResource, String optionsString) { + if(LOG.isDebugEnabled()) { + LOG.debug("==> RangerDefaultResourceMatcher.init(" + resourceDef + ", " + policyResource + ", " + optionsString + ")"); + } + + super.init(resourceDef, policyResource, optionsString); + + if(LOG.isDebugEnabled()) { + LOG.debug("<== RangerDefaultResourceMatcher.init(" + resourceDef + ", " + policyResource + ", " + optionsString + ")"); + } + } + + @Override + public boolean isMatch(String resource) { + if(LOG.isDebugEnabled()) { + LOG.debug("==> RangerDefaultResourceMatcher.isMatch(" + resource + ")"); + } + + boolean ret = false; + + if(resource != null) { + if(optIgnoreCase) { + resource = resource.toLowerCase(); + } + + for(String policyValue : policyValues) { + ret = optWildCard ? resource.matches(policyValue) : StringUtils.equals(resource, policyValue); + + if(ret) { + break; + } + } + } else { + ret = isMatchAny; + } + + if(policyIsExcludes) { + ret = !ret; + } + + if(LOG.isDebugEnabled()) { + LOG.debug("<== RangerDefaultResourceMatcher.isMatch(" + resource + "): " + ret); + } + + return ret; + } + + public StringBuilder toString(StringBuilder sb) { + sb.append("RangerDefaultResourceMatcher={"); + + super.toString(sb); + + sb.append("policyValues={"); + if(policyValues != null) { + for(String value : policyValues) { + sb.append(value).append(","); + } + } + sb.append("} "); + + sb.append("policyIsExcludes={").append(policyIsExcludes).append("} "); + + sb.append("}"); + + return sb; + } +} http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/217e1892/agents-common/src/main/java/org/apache/ranger/plugin/resourcematcher/RangerPathResourceMatcher.java ---------------------------------------------------------------------- diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/resourcematcher/RangerPathResourceMatcher.java b/agents-common/src/main/java/org/apache/ranger/plugin/resourcematcher/RangerPathResourceMatcher.java new file mode 100644 index 0000000..2cf3a68 --- /dev/null +++ b/agents-common/src/main/java/org/apache/ranger/plugin/resourcematcher/RangerPathResourceMatcher.java @@ -0,0 +1,151 @@ +/* + * 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.ranger.plugin.resourcematcher; + +import org.apache.commons.io.FilenameUtils; +import org.apache.commons.lang.StringUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.ranger.plugin.model.RangerPolicy.RangerPolicyResource; +import org.apache.ranger.plugin.model.RangerServiceDef.RangerResourceDef; + + +public class RangerPathResourceMatcher extends RangerAbstractResourceMatcher { + private static final Log LOG = LogFactory.getLog(RangerPathResourceMatcher.class); + + private boolean policyIsRecursive = false; + + @Override + public void init(RangerResourceDef resourceDef, RangerPolicyResource policyResource, String optionsString) { + if(LOG.isDebugEnabled()) { + LOG.debug("==> RangerPathResourceMatcher.init(" + resourceDef + ", " + policyResource + ", " + optionsString + ")"); + } + + super.init(resourceDef, policyResource, optionsString); + + policyIsRecursive = policyResource == null ? false : policyResource.getIsRecursive(); + + if(LOG.isDebugEnabled()) { + LOG.debug("<== RangerPathResourceMatcher.init(" + resourceDef + ", " + policyResource + ", " + optionsString + ")"); + } + } + + @Override + public boolean isMatch(String resource) { + if(LOG.isDebugEnabled()) { + LOG.debug("==> RangerPathResourceMatcher.isMatch(" + resource + ")"); + } + + boolean ret = false; + + if(resource != null) { + if(optIgnoreCase) { + resource = resource.toLowerCase(); + } + + for(String policyValue : policyValues) { + if(policyIsRecursive) { + ret = StringUtils.startsWith(resource, policyValue); + + if(! ret && optWildCard) { + ret = isRecursiveWildCardMatch(resource, policyValue) ; + } + } else { + ret = StringUtils.equals(resource, policyValue); + + if(! ret && optWildCard) { + ret = FilenameUtils.wildcardMatch(resource, policyValue); + } + } + + if(ret) { + break; + } + } + } else { + ret = isMatchAny; + } + + if(policyIsExcludes) { + ret = !ret; + } + + if(LOG.isDebugEnabled()) { + LOG.debug("<== RangerPathResourceMatcher.isMatch(" + resource + "): " + ret); + } + + return ret; + } + + private static boolean isRecursiveWildCardMatch(String pathToCheck, String wildcardPath) { + if(LOG.isDebugEnabled()) { + LOG.debug("==> RangerPathResourceMatcher.isRecursiveWildCardMatch(" + pathToCheck + ", " + wildcardPath + ")"); + } + + boolean ret = false; + + if (pathToCheck != null) { + StringBuilder sb = new StringBuilder() ; + + for(String p : pathToCheck.split(org.apache.hadoop.fs.Path.SEPARATOR) ) { + sb.append(p); + + boolean matchFound = FilenameUtils.wildcardMatch(sb.toString(), wildcardPath) ; + + if (matchFound) { + ret = true ; + + break; + } + + sb.append(org.apache.hadoop.fs.Path.SEPARATOR) ; + } + + sb = null; + } + + if(LOG.isDebugEnabled()) { + LOG.debug("<== RangerPathResourceMatcher.isRecursiveWildCardMatch(" + pathToCheck + ", " + wildcardPath + "): " + ret); + } + + return ret; + } + + public StringBuilder toString(StringBuilder sb) { + sb.append("RangerPathResourceMatcher={"); + + super.toString(sb); + + sb.append("policyValues={"); + if(policyValues != null) { + for(String value : policyValues) { + sb.append(value).append(","); + } + } + sb.append("} "); + + sb.append("policyIsExcludes={").append(policyIsExcludes).append("} "); + sb.append("policyIsRecursive={").append(policyIsRecursive).append("} "); + + sb.append("}"); + + return sb; + } +} http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/217e1892/agents-common/src/main/java/org/apache/ranger/plugin/resourcematcher/RangerResourceMatcher.java ---------------------------------------------------------------------- diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/resourcematcher/RangerResourceMatcher.java b/agents-common/src/main/java/org/apache/ranger/plugin/resourcematcher/RangerResourceMatcher.java new file mode 100644 index 0000000..c750cd8 --- /dev/null +++ b/agents-common/src/main/java/org/apache/ranger/plugin/resourcematcher/RangerResourceMatcher.java @@ -0,0 +1,35 @@ +/* + * 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.ranger.plugin.resourcematcher; + +import org.apache.ranger.plugin.model.RangerPolicy.RangerPolicyResource; +import org.apache.ranger.plugin.model.RangerServiceDef.RangerResourceDef; + +public interface RangerResourceMatcher { + void init(RangerResourceDef resourceDef, RangerPolicyResource policyResource, String optionsString); + + RangerResourceDef getResourceDef(); + + RangerPolicyResource getPolicyResource(); + + String getOptionsString(); + + boolean isMatch(String resource); +} http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/217e1892/agents-common/src/main/java/org/apache/ranger/plugin/service/RangerBasePlugin.java ---------------------------------------------------------------------- diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/service/RangerBasePlugin.java b/agents-common/src/main/java/org/apache/ranger/plugin/service/RangerBasePlugin.java new file mode 100644 index 0000000..8f1fa5f --- /dev/null +++ b/agents-common/src/main/java/org/apache/ranger/plugin/service/RangerBasePlugin.java @@ -0,0 +1,178 @@ +/* + * 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.ranger.plugin.service; + +import java.util.Collection; + +import org.apache.commons.lang.StringUtils; +import org.apache.ranger.authorization.hadoop.config.RangerConfiguration; +import org.apache.ranger.plugin.audit.RangerAuditHandler; +import org.apache.ranger.plugin.policyengine.RangerAccessRequest; +import org.apache.ranger.plugin.policyengine.RangerAccessResult; +import org.apache.ranger.plugin.policyengine.RangerPolicyEngine; +import org.apache.ranger.plugin.policyengine.RangerPolicyEngineImpl; +import org.apache.ranger.plugin.store.ServiceStore; +import org.apache.ranger.plugin.store.ServiceStoreFactory; +import org.apache.ranger.plugin.util.PolicyRefresher; + + +public class RangerBasePlugin { + private String serviceType = null; + private String serviceName = null; + private RangerPolicyEngine policyEngine = null; + private PolicyRefresher refresher = null; + + + public RangerBasePlugin(String serviceType) { + this.serviceType = serviceType; + } + + public String getServiceType() { + return serviceType; + } + + public String getServiceName() { + return serviceName; + } + + public RangerPolicyEngine getPolicyEngine() { + return policyEngine; + } + + public void init() { + RangerPolicyEngine policyEngine = new RangerPolicyEngineImpl(); + + init(policyEngine); + } + + public synchronized void init(RangerPolicyEngine policyEngine) { + cleanup(); + + + String serviceName = RangerConfiguration.getInstance().get("ranger.plugin." + serviceType + ".service.name"); + String serviceStoreClass = RangerConfiguration.getInstance().get("ranger.plugin." + serviceType + ".service.store.class", "org.apache.ranger.plugin.store.rest.ServiceRESTStore"); + String cacheDir = RangerConfiguration.getInstance().get("ranger.plugin." + serviceType + ".service.store.cache.dir", "/tmp"); + long pollingIntervalMs = RangerConfiguration.getInstance().getLong("ranger.plugin." + serviceType + ".service.store.pollIntervalMs", 30 * 1000); + + if(StringUtils.isEmpty(serviceName)) { + // get the serviceName from download URL: http://ranger-admin-host:port/service/assets/policyList/serviceName + String policyDownloadUrl = RangerConfiguration.getInstance().get("xasecure." + serviceType + ".policymgr.url"); + + if(! StringUtils.isEmpty(policyDownloadUrl)) { + int idx = policyDownloadUrl.lastIndexOf('/'); + + if(idx != -1) { + serviceName = policyDownloadUrl.substring(idx + 1); + } + } + } + + ServiceStore serviceStore = ServiceStoreFactory.instance().getServiceStore(serviceStoreClass); + + refresher = new PolicyRefresher(policyEngine, serviceType, serviceName, serviceStore, pollingIntervalMs, cacheDir); + refresher.startRefresher(); + this.policyEngine = policyEngine; + } + + public synchronized void cleanup() { + PolicyRefresher refresher = this.refresher; + + this.serviceName = null; + this.policyEngine = null; + this.refresher = null; + + if(refresher != null) { + refresher.stopRefresher(); + } + } + + public void setDefaultAuditHandler(RangerAuditHandler auditHandler) { + RangerPolicyEngine policyEngine = this.policyEngine; + + if(policyEngine != null) { + policyEngine.setDefaultAuditHandler(auditHandler); + } + } + + public RangerAuditHandler getDefaultAuditHandler() { + RangerPolicyEngine policyEngine = this.policyEngine; + + if(policyEngine != null) { + return policyEngine.getDefaultAuditHandler(); + } + + return null; + } + + + public RangerAccessResult createAccessResult(RangerAccessRequest request) { + RangerPolicyEngine policyEngine = this.policyEngine; + + if(policyEngine != null) { + return policyEngine.createAccessResult(request); + } + + return null; + } + + + public RangerAccessResult isAccessAllowed(RangerAccessRequest request) { + RangerPolicyEngine policyEngine = this.policyEngine; + + if(policyEngine != null) { + return policyEngine.isAccessAllowed(request); + } + + return null; + } + + + public Collection<RangerAccessResult> isAccessAllowed(Collection<RangerAccessRequest> requests) { + RangerPolicyEngine policyEngine = this.policyEngine; + + if(policyEngine != null) { + return policyEngine.isAccessAllowed(requests); + } + + return null; + } + + + public RangerAccessResult isAccessAllowed(RangerAccessRequest request, RangerAuditHandler auditHandler) { + RangerPolicyEngine policyEngine = this.policyEngine; + + if(policyEngine != null) { + return policyEngine.isAccessAllowed(request, auditHandler); + } + + return null; + } + + + public Collection<RangerAccessResult> isAccessAllowed(Collection<RangerAccessRequest> requests, RangerAuditHandler auditHandler) { + RangerPolicyEngine policyEngine = this.policyEngine; + + if(policyEngine != null) { + return policyEngine.isAccessAllowed(requests, auditHandler); + } + + return null; + } +} http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/217e1892/agents-common/src/main/java/org/apache/ranger/plugin/service/RangerBaseService.java ---------------------------------------------------------------------- diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/service/RangerBaseService.java b/agents-common/src/main/java/org/apache/ranger/plugin/service/RangerBaseService.java new file mode 100644 index 0000000..8eeb439 --- /dev/null +++ b/agents-common/src/main/java/org/apache/ranger/plugin/service/RangerBaseService.java @@ -0,0 +1,55 @@ +/* + * 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.ranger.plugin.service; + +import java.util.List; + +import org.apache.ranger.plugin.model.RangerService; +import org.apache.ranger.plugin.model.RangerServiceDef; + + +public abstract class RangerBaseService { + private RangerServiceDef serviceDef; + private RangerService service; + + + public void init(RangerServiceDef serviceDef, RangerService service) { + this.serviceDef = serviceDef; + this.service = service; + } + + /** + * @return the serviceDef + */ + public RangerServiceDef getServiceDef() { + return serviceDef; + } + + /** + * @return the service + */ + public RangerService getService() { + return service; + } + + public abstract void validateConfig() throws Exception; + + public abstract List<String> lookupResource(ResourceLookupContext context) throws Exception; +} http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/217e1892/agents-common/src/main/java/org/apache/ranger/plugin/service/ResourceLookupContext.java ---------------------------------------------------------------------- diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/service/ResourceLookupContext.java b/agents-common/src/main/java/org/apache/ranger/plugin/service/ResourceLookupContext.java new file mode 100644 index 0000000..b5c3dda --- /dev/null +++ b/agents-common/src/main/java/org/apache/ranger/plugin/service/ResourceLookupContext.java @@ -0,0 +1,72 @@ +/* + * 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.ranger.plugin.service; + +import java.util.List; +import java.util.Map; + + +public class ResourceLookupContext { + private String userInput; + private String resourceName; + private Map<String, List<String>> resources; + + + public ResourceLookupContext() { + + } + + /** + * @return the userInput + */ + public String getUserInput() { + return userInput; + } + /** + * @param userInput the userInput to set + */ + public void setUserInput(String userInput) { + this.userInput = userInput; + } + /** + * @return the resourceName + */ + public String getResourceName() { + return resourceName; + } + /** + * @param resourceName the resourceName to set + */ + public void setResourceName(String resourceName) { + this.resourceName = resourceName; + } + /** + * @return the resources + */ + public Map<String, List<String>> getResources() { + return resources; + } + /** + * @param resources the resources to set + */ + public void setResources(Map<String, List<String>> resources) { + this.resources = resources; + } +} http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/217e1892/agents-common/src/main/java/org/apache/ranger/plugin/store/ServiceStore.java ---------------------------------------------------------------------- diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/store/ServiceStore.java b/agents-common/src/main/java/org/apache/ranger/plugin/store/ServiceStore.java new file mode 100644 index 0000000..e8d970c --- /dev/null +++ b/agents-common/src/main/java/org/apache/ranger/plugin/store/ServiceStore.java @@ -0,0 +1,74 @@ +/* + * 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.ranger.plugin.store; + +import java.util.List; + +import org.apache.ranger.plugin.model.RangerPolicy; +import org.apache.ranger.plugin.model.RangerService; +import org.apache.ranger.plugin.model.RangerServiceDef; +import org.apache.ranger.plugin.util.SearchFilter; +import org.apache.ranger.plugin.util.ServicePolicies; + +public interface ServiceStore { + void init() throws Exception; + + RangerServiceDef createServiceDef(RangerServiceDef serviceDef) throws Exception; + + RangerServiceDef updateServiceDef(RangerServiceDef serviceDef) throws Exception; + + void deleteServiceDef(Long id) throws Exception; + + RangerServiceDef getServiceDef(Long id) throws Exception; + + RangerServiceDef getServiceDefByName(String name) throws Exception; + + List<RangerServiceDef> getServiceDefs(SearchFilter filter) throws Exception; + + + RangerService createService(RangerService service) throws Exception; + + RangerService updateService(RangerService service) throws Exception; + + void deleteService(Long id) throws Exception; + + RangerService getService(Long id) throws Exception; + + RangerService getServiceByName(String name) throws Exception; + + List<RangerService> getServices(SearchFilter filter) throws Exception; + + + RangerPolicy createPolicy(RangerPolicy policy) throws Exception; + + RangerPolicy updatePolicy(RangerPolicy policy) throws Exception; + + void deletePolicy(Long id) throws Exception; + + RangerPolicy getPolicy(Long id) throws Exception; + + List<RangerPolicy> getPolicies(SearchFilter filter) throws Exception; + + List<RangerPolicy> getServicePolicies(Long serviceId, SearchFilter filter) throws Exception; + + List<RangerPolicy> getServicePolicies(String serviceName, SearchFilter filter) throws Exception; + + ServicePolicies getServicePoliciesIfUpdated(String serviceName, Long lastKnownVersion) throws Exception; +} http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/217e1892/agents-common/src/main/java/org/apache/ranger/plugin/store/ServiceStoreFactory.java ---------------------------------------------------------------------- diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/store/ServiceStoreFactory.java b/agents-common/src/main/java/org/apache/ranger/plugin/store/ServiceStoreFactory.java new file mode 100644 index 0000000..f9a2404 --- /dev/null +++ b/agents-common/src/main/java/org/apache/ranger/plugin/store/ServiceStoreFactory.java @@ -0,0 +1,113 @@ +/* + * 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.ranger.plugin.store; + +import java.util.HashMap; +import java.util.Map; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.ranger.authorization.hadoop.config.RangerConfiguration; + + +public class ServiceStoreFactory { + private static final Log LOG = LogFactory.getLog(ServiceStoreFactory.class); + + private static ServiceStoreFactory sInstance = null; + + private Map<String, ServiceStore> serviceStores = null; + private ServiceStore defaultServiceStore = null; + + + public static ServiceStoreFactory instance() { + if(sInstance == null) { + sInstance = new ServiceStoreFactory(); + } + + return sInstance; + } + + public ServiceStore getServiceStore() { + ServiceStore ret = defaultServiceStore; + + if(ret == null) { // if no service store has been created yet, create the default store. TODO: review the impact and update, if necessary + String defaultServiceStoreClass = RangerConfiguration.getInstance().get("ranger.default.service.store.class", "org.apache.ranger.plugin.store.file.ServiceFileStore"); + + ret = getServiceStore(defaultServiceStoreClass); + } + + return ret; + } + + public ServiceStore getServiceStore(String storeClassname) { + ServiceStore ret = serviceStores.get(storeClassname); + + if(ret == null) { + synchronized(this) { + ret = serviceStores.get(storeClassname); + + if(ret == null) { + try { + @SuppressWarnings("unchecked") + Class<ServiceStore> storeClass = (Class<ServiceStore>)Class.forName(storeClassname); + + ret = storeClass.newInstance(); + + ret.init(); + + serviceStores.put(storeClassname, ret); + + if(defaultServiceStore == null) { + defaultServiceStore = ret; + } + } catch(Exception excp) { + LOG.error("failed to instantiate service store of type " + storeClassname, excp); + } + } + } + } + + return ret; + } + + private ServiceStoreFactory() { + if(LOG.isDebugEnabled()) { + LOG.debug("==> ServiceStoreFactory.ServiceStoreFactory()"); + } + + init(); + + if(LOG.isDebugEnabled()) { + LOG.debug("<== ServiceStoreFactory.ServiceStoreFactory()"); + } + } + + private void init() { + if(LOG.isDebugEnabled()) { + LOG.debug("==> ServiceStoreFactory.init()"); + } + + serviceStores = new HashMap<String, ServiceStore>(); + + if(LOG.isDebugEnabled()) { + LOG.debug("<== ServiceStoreFactory.init()"); + } + } +} http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/217e1892/agents-common/src/main/java/org/apache/ranger/plugin/store/file/BaseFileStore.java ---------------------------------------------------------------------- diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/store/file/BaseFileStore.java b/agents-common/src/main/java/org/apache/ranger/plugin/store/file/BaseFileStore.java new file mode 100644 index 0000000..17b46f9 --- /dev/null +++ b/agents-common/src/main/java/org/apache/ranger/plugin/store/file/BaseFileStore.java @@ -0,0 +1,390 @@ +/* + * 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.ranger.plugin.store.file; + +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStreamWriter; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.UUID; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.hadoop.conf.Configuration; +import org.apache.hadoop.fs.FSDataInputStream; +import org.apache.hadoop.fs.FSDataOutputStream; +import org.apache.hadoop.fs.FileStatus; +import org.apache.hadoop.fs.FileSystem; +import org.apache.hadoop.fs.Path; +import org.apache.hadoop.fs.PathFilter; +import org.apache.ranger.authorization.hadoop.config.RangerConfiguration; +import org.apache.ranger.plugin.model.RangerBaseModelObject; +import org.apache.ranger.plugin.model.RangerPolicy; +import org.apache.ranger.plugin.model.RangerService; +import org.apache.ranger.plugin.model.RangerServiceDef; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; + +public class BaseFileStore { + private static final Log LOG = LogFactory.getLog(BaseFileStore.class); + + private Gson gsonBuilder = null; + private String dataDir = null; + + protected static String FILE_PREFIX_SERVICE_DEF = "ranger-servicedef-"; + protected static String FILE_PREFIX_SERVICE = "ranger-service-"; + protected static String FILE_PREFIX_POLICY = "ranger-policy-"; + protected static String FILE_SUFFIX_JSON = ".json"; + + + protected void initStore() { + dataDir = RangerConfiguration.getInstance().get("ranger.service.store.file.dir", "file:///etc/ranger/data"); + + try { + gsonBuilder = new GsonBuilder().setDateFormat("yyyyMMdd-HH:mm:ss.SSS-Z").setPrettyPrinting().create(); + } catch(Throwable excp) { + LOG.fatal("BaseFileStore.init(): failed to create GsonBuilder object", excp); + } + } + + protected String getDataDir() { + return dataDir; + } + + protected String getServiceDefFile(Long id) { + String filePath = dataDir + Path.SEPARATOR + FILE_PREFIX_SERVICE_DEF + id + FILE_SUFFIX_JSON; + + return filePath; + } + + protected String getServiceFile(Long id) { + String filePath = dataDir + Path.SEPARATOR + FILE_PREFIX_SERVICE + id + FILE_SUFFIX_JSON; + + return filePath; + } + + protected String getPolicyFile(Long serviceId, Long policyId) { + String filePath = dataDir + Path.SEPARATOR + FILE_PREFIX_POLICY + serviceId + "-" + policyId + FILE_SUFFIX_JSON; + + return filePath; + } + + protected <T> T loadFromResource(String resource, Class<T> cls) throws Exception { + if(LOG.isDebugEnabled()) { + LOG.debug("==> BaseFileStore.loadFromResource(" + resource + ")"); + } + + InputStream inStream = this.getClass().getResourceAsStream(resource); + + T ret = loadFromStream(inStream, cls); + + if(LOG.isDebugEnabled()) { + LOG.debug("<== BaseFileStore.loadFromResource(" + resource + "): " + ret); + } + + return ret; + } + + protected <T> T loadFromStream(InputStream inStream, Class<T> cls) throws Exception { + if(LOG.isDebugEnabled()) { + LOG.debug("==> BaseFileStore.loadFromStream()"); + } + + InputStreamReader reader = new InputStreamReader(inStream); + + T ret = gsonBuilder.fromJson(reader, cls); + + if(LOG.isDebugEnabled()) { + LOG.debug("<== BaseFileStore.loadFromStream(): " + ret); + } + + return ret; + } + + protected <T> T loadFromFile(Path filePath, Class<T> cls) throws Exception { + if(LOG.isDebugEnabled()) { + LOG.debug("==> BaseFileStore.loadFromFile(" + filePath + ")"); + } + + T ret = null; + InputStreamReader reader = null; + + try { + FileSystem fileSystem = getFileSystem(filePath); + FSDataInputStream inStream = fileSystem.open(filePath); + + ret = loadFromStream(inStream, cls); + } finally { + close(reader); + } + + if(LOG.isDebugEnabled()) { + LOG.debug("<== BaseFileStore.loadFromFile(" + filePath + "): " + ret); + } + + return ret; + } + + protected <T> List<T> loadFromDir(Path dirPath, final String filePrefix, Class<T> cls) throws Exception { + if(LOG.isDebugEnabled()) { + LOG.debug("==> BaseFileStore.loadFromDir()"); + } + + List<T> ret = new ArrayList<T>(); + + try { + FileSystem fileSystem = getFileSystem(dirPath); + + if(fileSystem.exists(dirPath) && fileSystem.isDirectory(dirPath)) { + PathFilter filter = new PathFilter() { + @Override + public boolean accept(Path path) { + return path.getName().startsWith(filePrefix) && + path.getName().endsWith(FILE_SUFFIX_JSON); + } + }; + + FileStatus[] sdFiles = fileSystem.listStatus(dirPath, filter); + + if(sdFiles != null) { + for(FileStatus sdFile : sdFiles) { + T obj = loadFromFile(sdFile.getPath(), cls); + + if(obj != null) { + ret.add(obj); + } + } + } + } else { + LOG.error(dirPath + ": does not exists or not a directory"); + } + } catch(IOException excp) { + LOG.warn("error loading service-def in directory " + dirPath, excp); + } + + if(LOG.isDebugEnabled()) { + LOG.debug("<== BaseFileStore.loadFromDir(): count=" + (ret == null ? 0 : ret.size())); + } + + return ret; + } + + protected <T> T saveToFile(T obj, Path filePath, boolean overWrite) throws Exception { + if(LOG.isDebugEnabled()) { + LOG.debug("==> BaseFileStore.saveToFile(" + filePath + ")"); + } + + OutputStreamWriter writer = null; + + try { + FileSystem fileSystem = getFileSystem(filePath); + FSDataOutputStream outStream = fileSystem.create(filePath, overWrite); + + writer = new OutputStreamWriter(outStream); + + gsonBuilder.toJson(obj, writer); + } finally { + close(writer); + } + + if(LOG.isDebugEnabled()) { + LOG.debug("<== BaseFileStore.saveToFile(" + filePath + "): " + obj); + } + + return obj; + } + + protected boolean deleteFile(Path filePath) throws Exception { + LOG.debug("==> BaseFileStore.deleteFile(" + filePath + ")"); + + FileSystem fileSystem = getFileSystem(filePath); + + boolean ret = false; + + if(fileSystem.exists(filePath)) { + ret = fileSystem.delete(filePath, false); + } else { + ret = true; // nothing to delete + } + + LOG.debug("<== BaseFileStore.deleteFile(" + filePath + "): " + ret); + + return ret; + } + + protected boolean renamePath(Path oldPath, Path newPath) throws Exception { + if(LOG.isDebugEnabled()) { + LOG.debug("==> BaseFileStore.renamePath(" + oldPath + "," + newPath + ")"); + } + + FileSystem fileSystem = getFileSystem(oldPath); + + boolean ret = false; + + if(fileSystem.exists(oldPath)) { + if(! fileSystem.exists(newPath)) { + ret = fileSystem.rename(oldPath, newPath); + } else { + LOG.warn("target of rename '" + newPath + "' already exists"); + } + } + + if(LOG.isDebugEnabled()) { + LOG.debug("<== BaseFileStore.renamePath(" + oldPath + "," + newPath + "): " + ret); + } + + return ret; + } + + protected RangerServiceDef saveToFile(RangerServiceDef serviceDef, boolean overWrite) throws Exception { + if(LOG.isDebugEnabled()) { + LOG.debug("==> BaseFileStore.saveToFile(" + serviceDef + "," + overWrite + ")"); + } + + Path filePath = new Path(getServiceDefFile(serviceDef.getId())); + + RangerServiceDef ret = saveToFile(serviceDef, filePath, overWrite); + + if(LOG.isDebugEnabled()) { + LOG.debug("<== BaseFileStore.saveToFile(" + serviceDef + "," + overWrite + "): "); + } + + return ret; + } + + protected RangerService saveToFile(RangerService service, boolean overWrite) throws Exception { + Path filePath = new Path(getServiceFile(service.getId())); + + RangerService ret = saveToFile(service, filePath, overWrite); + + return ret; + } + + protected RangerPolicy saveToFile(RangerPolicy policy, long serviceId, boolean overWrite) throws Exception { + Path filePath = new Path(getPolicyFile(serviceId, policy.getId())); + + RangerPolicy ret = saveToFile(policy, filePath, overWrite); + + return ret; + } + + protected long getMaxId(List<? extends RangerBaseModelObject> objs) { + long ret = -1; + + if(objs != null) { + for(RangerBaseModelObject obj : objs) { + if(obj.getId() > ret) { + ret = obj.getId(); + } + } + } + + return ret; + } + protected FileSystem getFileSystem(Path filePath) throws Exception { + Configuration conf = new Configuration(); + FileSystem fileSystem = filePath.getFileSystem(conf); + + return fileSystem; + } + + protected void close(FileSystem fs) { + if(fs != null) { + try { + fs.close(); + } catch(IOException excp) { + // ignore + } + } + } + + protected void close(InputStreamReader reader) { + if(reader != null) { + try { + reader.close(); + } catch(IOException excp) { + // ignore + } + } + } + + protected void close(OutputStreamWriter writer) { + if(writer != null) { + try { + writer.close(); + } catch(IOException excp) { + // ignore + } + } + } + + protected void preCreate(RangerBaseModelObject obj) { + obj.setId(new Long(0)); + obj.setGuid(UUID.randomUUID().toString()); + obj.setCreateTime(new Date()); + obj.setUpdateTime(obj.getCreateTime()); + obj.setVersion(new Long(1)); + } + + protected void postCreate(RangerBaseModelObject obj) { + // TODO: + } + + protected void preUpdate(RangerBaseModelObject obj) { + if(obj.getId() == null) { + obj.setId(new Long(0)); + } + + if(obj.getGuid() == null) { + obj.setGuid(UUID.randomUUID().toString()); + } + + if(obj.getCreateTime() == null) { + obj.setCreateTime(new Date()); + } + + Long version = obj.getVersion(); + + if(version == null) { + version = new Long(1); + } else { + version = new Long(version.longValue() + 1); + } + + obj.setVersion(version); + obj.setUpdateTime(new Date()); + } + + protected void postUpdate(RangerBaseModelObject obj) { + // TODO: + } + + protected void preDelete(RangerBaseModelObject obj) { + // TODO: + } + + protected void postDelete(RangerBaseModelObject obj) { + // TODO: + } +}
