RANGER-256: sample condition evaluators to demonstrate dynamic conditions
Project: http://git-wip-us.apache.org/repos/asf/incubator-ranger/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-ranger/commit/78889721 Tree: http://git-wip-us.apache.org/repos/asf/incubator-ranger/tree/78889721 Diff: http://git-wip-us.apache.org/repos/asf/incubator-ranger/diff/78889721 Branch: refs/heads/master Commit: 788897211404666cbdbed19316cba65e3afacffa Parents: c59617d Author: Alok Lal <[email protected]> Authored: Sat Feb 21 09:22:51 2015 -0800 Committer: Madhan Neethiraj <[email protected]> Committed: Sat Feb 21 09:22:51 2015 -0800 ---------------------------------------------------------------------- .../conditionevaluator/RangerSimpleMatcher.java | 129 +++++++++++ .../RangerTimeOfDayMatcher.java | 201 +++++++++++++++++ .../RangerSimpleMatcherTest.java | 122 +++++++++++ .../RangerTimeOfDayMatcherTest.java | 215 +++++++++++++++++++ .../src/test/resources/log4j.properties | 36 ++++ 5 files changed, 703 insertions(+) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/78889721/agents-common/src/main/java/org/apache/ranger/plugin/conditionevaluator/RangerSimpleMatcher.java ---------------------------------------------------------------------- diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/conditionevaluator/RangerSimpleMatcher.java b/agents-common/src/main/java/org/apache/ranger/plugin/conditionevaluator/RangerSimpleMatcher.java new file mode 100644 index 0000000..e0bcefc --- /dev/null +++ b/agents-common/src/main/java/org/apache/ranger/plugin/conditionevaluator/RangerSimpleMatcher.java @@ -0,0 +1,129 @@ +/* + * 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.conditionevaluator; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.commons.collections.CollectionUtils; +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.RangerPolicyItemCondition; +import org.apache.ranger.plugin.model.RangerServiceDef.RangerPolicyConditionDef; +import org.apache.ranger.plugin.policyengine.RangerAccessRequest; + +public class RangerSimpleMatcher implements RangerConditionEvaluator { + + private static final Log LOG = LogFactory.getLog(RangerSimpleMatcher.class); + private boolean _allowAny = false; + private String ConditionName = null; + private List<String> _values = new ArrayList<String>(); + + @Override + public void init(RangerPolicyConditionDef conditionDef, RangerPolicyItemCondition condition) { + if(LOG.isDebugEnabled()) { + LOG.debug("==> RangerSimpleMatcher.init(" + condition + ")"); + } + + if (condition == null) { + LOG.debug("init: null policy condition! Will match always!"); + _allowAny = true; + } else if (conditionDef == null) { + LOG.debug("init: null policy condition definition! Will match always!"); + _allowAny = true; + } else if (CollectionUtils.isEmpty(condition.getValues())) { + LOG.debug("init: empty conditions collection on policy condition! Will match always!"); + _allowAny = true; + } else if (StringUtils.isEmpty(conditionDef.getEvaluatorOptions())) { + LOG.debug("init: Evaluator options were empty. Can't determine what value to use from context. Will match always."); + _allowAny = true; + } else { + ConditionName = conditionDef.getEvaluatorOptions(); + for (String value : condition.getValues()) { + _values.add(value); + } + } + + if(LOG.isDebugEnabled()) { + LOG.debug("<== RangerSimpleMatcher.init(" + condition + "): countries[" + _values + "]"); + } + + } + + @Override + public boolean isMatched(RangerAccessRequest request) { + + if(LOG.isDebugEnabled()) { + LOG.debug("==> RangerSimpleMatcher.isMatched(" + request + ")"); + } + + boolean matched = true; + if (_allowAny) { + LOG.debug("isMatched: allowAny flag is true. Matched!"); + } else { + String requestValue = extractValue(request, ConditionName); + if (requestValue == null) { + LOG.debug("isMatched: couldn't get value from request. Ok. Implicitly matched!"); + } else { + matched = false; + for (String policyValue : _values) { + if (FilenameUtils.wildcardMatch(requestValue, policyValue)) { + matched = true; + break; + } + } + } + } + + if(LOG.isDebugEnabled()) { + LOG.debug("<== RangerSimpleMatcher.isMatched(" + request+ "): " + matched); + } + + return matched; + } + + String extractValue(final RangerAccessRequest request, String key) { + if(LOG.isDebugEnabled()) { + LOG.debug("==> RangerSimpleMatcher.extractValue(" + request+ ")"); + } + + String value = null; + if (request == null) { + LOG.debug("isMatched: Unexpected: null request. Returning null!"); + } else if (request.getContext() == null) { + LOG.debug("isMatched: Context map of request is null. Ok. Returning null!"); + } else if (CollectionUtils.isEmpty(request.getContext().entrySet())) { + LOG.debug("isMatched: Missing context on request. Ok. Condition isn't applicable. Returning null!"); + } else if (!request.getContext().containsKey(key)) { + if (LOG.isDebugEnabled()) { + LOG.debug("isMatched: Unexpected: Context did not have data for condition[" + key + "]. Returning null!"); + } + } else { + value = (String)request.getContext().get(key); + } + + if(LOG.isDebugEnabled()) { + LOG.debug("<== RangerSimpleMatcher.extractValue(" + request+ "): " + value); + } + return value; + } +} http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/78889721/agents-common/src/main/java/org/apache/ranger/plugin/conditionevaluator/RangerTimeOfDayMatcher.java ---------------------------------------------------------------------- diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/conditionevaluator/RangerTimeOfDayMatcher.java b/agents-common/src/main/java/org/apache/ranger/plugin/conditionevaluator/RangerTimeOfDayMatcher.java new file mode 100644 index 0000000..e8bb8db --- /dev/null +++ b/agents-common/src/main/java/org/apache/ranger/plugin/conditionevaluator/RangerTimeOfDayMatcher.java @@ -0,0 +1,201 @@ +/* + * 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.conditionevaluator; + +import java.util.ArrayList; +import java.util.Calendar; +import java.util.Date; +import java.util.GregorianCalendar; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +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.RangerPolicyItemCondition; +import org.apache.ranger.plugin.model.RangerServiceDef.RangerPolicyConditionDef; +import org.apache.ranger.plugin.policyengine.RangerAccessRequest; + +public class RangerTimeOfDayMatcher implements RangerConditionEvaluator { + + private static final Log LOG = LogFactory.getLog(RangerTimeOfDayMatcher.class); + boolean _allowAny = false; + List<int[]> _durations = new ArrayList<int[]>(); + + @Override + public void init(RangerPolicyConditionDef conditionDef, RangerPolicyItemCondition condition) { + if(LOG.isDebugEnabled()) { + LOG.debug("==> RangerTimeOfDayMatcher.init(" + condition + ")"); + } + + if (condition == null) { + LOG.debug("init: null policy condition! Will match always!"); + _allowAny = true; + } else if (CollectionUtils.isEmpty(condition.getValues())) { + LOG.debug("init: empty conditions collection on policy condition! Will match always!"); + _allowAny = true; + } else { + for (String value : condition.getValues()) { + if (StringUtils.isEmpty(value)) { + LOG.warn("init: Unexpected: one of the value in condition is null or empty!"); + } else { + int[] aDuration = extractDuration(value); + if (aDuration != null) { + _durations.add(aDuration); + } + } + } + } + + if (_durations.isEmpty()) { + LOG.debug("No valid durations found. Will always match!"); + _allowAny = true; + } + + if(LOG.isDebugEnabled()) { + LOG.debug("<== RangerTimeOfDayMatcher.init(" + condition + "): countries[" + _durations + "]"); + } + } + + // match "9am-5pm", "9 Am - 5 PM", "9 am.- 5 P.M", "9:30 AM - 4:00p.m." etc. spaces around - and after digits are allowed and dots in am/pm string in mixed cases is allowed + static final Pattern _Pattern = Pattern.compile(" *(\\d{1,2})(:(\\d{1,2}))? *([aApP])\\.?[mM]\\.? *- *(\\d{1,2})(:(\\d{1,2}))? *([aApP])\\.?[mM]\\.? *"); + + int[] extractDuration(String value) { + if(LOG.isDebugEnabled()) { + LOG.debug("==> RangerTimeOfDayMatcher.extractDuration(" + value + ")"); + } + + int[] result = null; + if (value == null) { + LOG.warn("extractDuration: null input value!"); + } else { + Matcher m = _Pattern.matcher(value); + if (!m.matches()) { + LOG.warn("extractDuration: input[" + value + "] did not match pattern!"); + } else { + int startHour = Integer.parseInt(m.group(1)); + int startMin = 0; + if (m.group(3) != null) { + startMin = Integer.parseInt(m.group(3)); + } + String startType = m.group(4).toUpperCase(); + + int endHour = Integer.parseInt(m.group(5)); + int endMinute = 0; + if (m.group(7) != null) { + endMinute = Integer.parseInt(m.group(7)); + } + String endType = m.group(8).toUpperCase(); + if (startType.equals("P") && endType.equals("A")) { + LOG.warn("extractDuration: Invalid duration:" + value); + } else { + if (startType.equals("P")) { + startHour += 12; + } + if (endType.equals("P")) { + endHour += 12; + } + result = new int[] { (startHour*60)+startMin, (endHour*60)+endMinute }; + } + } + } + + if(LOG.isDebugEnabled()) { + LOG.debug("<== RangerTimeOfDayMatcher.extractDuration(" + value + "): duration[" + result + "]"); + } + return result; + } + + @Override + public boolean isMatched(RangerAccessRequest request) { + + if(LOG.isDebugEnabled()) { + LOG.debug("==> RangerTimeOfDayMatcher.isMatched(" + request + ")"); + } + + boolean matched = true; + if (_allowAny) { + LOG.debug("isMatched: allowAny flag is true. Matched!"); + } else if (request == null) { + LOG.warn("isMatched: Unexpected: Request is null! Implicitly matched!"); + } else if (request.getAccessTime() == null) { + LOG.warn("isMatched: Unexpected: Accesstime on the request is null! Implicitly matched!"); + } else { + Date date = request.getAccessTime(); + Calendar calendar = GregorianCalendar.getInstance(); + calendar.setTime(date); + int hourOfDay = calendar.get(Calendar.HOUR_OF_DAY); + int minutes = calendar.get(Calendar.MINUTE); + if (durationMatched(_durations, hourOfDay, minutes)) { + if (LOG.isDebugEnabled()) { + LOG.debug("isMatched: None of the durations contains this hour of day[" + hourOfDay + "]"); + } + } else { + matched = false; + } + } + + if(LOG.isDebugEnabled()) { + LOG.debug("<== RangerTimeOfDayMatcher.isMatched(" + request+ "): " + matched); + } + + return matched; + } + + boolean durationMatched(List<int[]> durations, int hourOfDay, int minutes) { + for (int[] aDuration : durations) { + int start = aDuration[0]; + int end = aDuration[1]; + int minutesOfDay = hourOfDay*60 + minutes; + if (start <= minutesOfDay && minutesOfDay <= end) { + return true; + } + } + return false; + } + + String extractValue(final RangerAccessRequest request, String key) { + if(LOG.isDebugEnabled()) { + LOG.debug("==> RangerSimpleMatcher.extractValue(" + request+ ")"); + } + + String value = null; + if (request == null) { + LOG.debug("isMatched: Unexpected: null request. Returning null!"); + } else if (request.getContext() == null) { + LOG.debug("isMatched: Context map of request is null. Ok. Returning null!"); + } else if (CollectionUtils.isEmpty(request.getContext().entrySet())) { + LOG.debug("isMatched: Missing context on request. Ok. Condition isn't applicable. Returning null!"); + } else if (!request.getContext().containsKey(key)) { + if (LOG.isDebugEnabled()) { + LOG.debug("isMatched: Unexpected: Context did not have data for condition[" + key + "]. Returning null!"); + } + } else { + value = (String)request.getContext().get(key); + } + + if(LOG.isDebugEnabled()) { + LOG.debug("<== RangerSimpleMatcher.extractValue(" + request+ "): " + value); + } + return value; + } +} http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/78889721/agents-common/src/test/java/org/apache/ranger/plugin/conditionevaluator/RangerSimpleMatcherTest.java ---------------------------------------------------------------------- diff --git a/agents-common/src/test/java/org/apache/ranger/plugin/conditionevaluator/RangerSimpleMatcherTest.java b/agents-common/src/test/java/org/apache/ranger/plugin/conditionevaluator/RangerSimpleMatcherTest.java new file mode 100644 index 0000000..4bd2a43 --- /dev/null +++ b/agents-common/src/test/java/org/apache/ranger/plugin/conditionevaluator/RangerSimpleMatcherTest.java @@ -0,0 +1,122 @@ +/* + * 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.conditionevaluator; + + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.ranger.plugin.model.RangerPolicy.RangerPolicyItemCondition; +import org.apache.ranger.plugin.model.RangerServiceDef.RangerPolicyConditionDef; +import org.apache.ranger.plugin.policyengine.RangerAccessRequest; +import org.junit.Test; + +public class RangerSimpleMatcherTest { + + final String _conditionOption = "key1"; + @Test + public void testIsMatched_happyPath() { + // this documents some unexpected behavior of the ip matcher + RangerSimpleMatcher ipMatcher = createMatcher(new String[]{"US", "C*"} ); + assertTrue(ipMatcher.isMatched(createRequest("US"))); + assertTrue(ipMatcher.isMatched(createRequest("CA"))); + assertTrue(ipMatcher.isMatched(createRequest("C---"))); + assertFalse(ipMatcher.isMatched(createRequest(" US "))); + assertFalse(ipMatcher.isMatched(createRequest("Us"))); + assertFalse(ipMatcher.isMatched(createRequest("ca"))); + } + + @Test + public void test_firewallings() { + + // create a request for some policyValue, say, country and use it to match against matcher initialized with all sorts of bad data + RangerAccessRequest request = createRequest("AB"); + + RangerSimpleMatcher matcher = new RangerSimpleMatcher(); + // Matcher initialized with null policy should behave sensibly! It matches everything! + matcher.init(null, null); + assertTrue(matcher.isMatched(request)); + + RangerPolicyItemCondition policyItemCondition = mock(RangerPolicyItemCondition.class); + matcher.init(null, policyItemCondition); + assertTrue(matcher.isMatched(request)); + + RangerPolicyConditionDef conditionDef = mock(RangerPolicyConditionDef.class); + matcher.init(conditionDef, null); + assertTrue(matcher.isMatched(request)); + + // so should a policy item condition with initialized with null list of values + when(policyItemCondition.getValues()).thenReturn(null); + matcher.init(conditionDef, policyItemCondition); + assertTrue(matcher.isMatched(request)); + + // not null item condition with empty condition list + List<String> values = new ArrayList<String>(); + when(policyItemCondition.getValues()).thenReturn(values); + matcher.init(conditionDef, policyItemCondition); + assertTrue(matcher.isMatched(request)); + + // values as sensible items in it, however, the conditionDef has null evaluator option, so that too suppresses any check + values.add("AB"); + when(policyItemCondition.getValues()).thenReturn(values); + when(conditionDef.getEvaluatorOptions()).thenReturn(null); + matcher.init(conditionDef, policyItemCondition); + assertTrue(matcher.isMatched(request)); + + // If evaluator option on the condition def is non-null then it starts to evaluate for real + when(conditionDef.getEvaluatorOptions()).thenReturn(_conditionOption); + matcher.init(conditionDef, policyItemCondition); + assertTrue(matcher.isMatched(request)); + } + + RangerSimpleMatcher createMatcher(String[] ipArray) { + RangerSimpleMatcher matcher = new RangerSimpleMatcher(); + + if (ipArray == null) { + matcher.init(null, null); + } else { + RangerPolicyItemCondition condition = mock(RangerPolicyItemCondition.class); + List<String> addresses = Arrays.asList(ipArray); + when(condition.getValues()).thenReturn(addresses); + + RangerPolicyConditionDef conditionDef = mock(RangerPolicyConditionDef.class); + when(conditionDef.getEvaluatorOptions()).thenReturn(_conditionOption); + matcher.init(conditionDef, condition); + } + + return matcher; + } + + RangerAccessRequest createRequest(String value) { + Map<String, Object> context = new HashMap<String, Object>(); + context.put(_conditionOption, value); + RangerAccessRequest request = mock(RangerAccessRequest.class); + when(request.getContext()).thenReturn(context); + return request; + } +} http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/78889721/agents-common/src/test/java/org/apache/ranger/plugin/conditionevaluator/RangerTimeOfDayMatcherTest.java ---------------------------------------------------------------------- diff --git a/agents-common/src/test/java/org/apache/ranger/plugin/conditionevaluator/RangerTimeOfDayMatcherTest.java b/agents-common/src/test/java/org/apache/ranger/plugin/conditionevaluator/RangerTimeOfDayMatcherTest.java new file mode 100644 index 0000000..21e4769 --- /dev/null +++ b/agents-common/src/test/java/org/apache/ranger/plugin/conditionevaluator/RangerTimeOfDayMatcherTest.java @@ -0,0 +1,215 @@ +/* + * 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.conditionevaluator; + +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.util.Arrays; +import java.util.Calendar; +import java.util.Date; +import java.util.GregorianCalendar; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.apache.ranger.plugin.model.RangerPolicy.RangerPolicyItemCondition; +import org.apache.ranger.plugin.policyengine.RangerAccessRequest; +import org.junit.Test; + +import com.google.common.collect.Lists; + +public class RangerTimeOfDayMatcherTest { + + final Pattern p = RangerTimeOfDayMatcher._Pattern; + + @Test + public void test_patterMatching_happyPath() { + // sensible values and some goofy ones work + String[] durations = new String[] { + "9am-5pm", " 9Am -5 Pm", " 9Am -5 Pm", "9 AM -5 p.m.", "9a.M - 5Pm.", + "9:30am-5:30pm", " 9:00Am -5:59 Pm", + " 9 am - 4 pm " + }; + check(durations, true); + } + + @Test + public void test_patterMatching_unexpectedMatches() { + // even semantically illegal durations work -- parsing is just for format not for semantics! + String[] durations = new String[] { + "9pm-5AM", // illegal duration where start > end is allows parsed as right! + "00PM-44PM", // any two digits are allowed! + "9:0am-5:7pm", // Minute part can be one digit + }; + check(durations, true); + } + + @Test + public void test_patterMatching_misMatches() { + // clearly invalid values don't match. + String[] durations = new String[] { + "9am", "-", "", "9-5", "9-10am", "9pm-6", + "009AM-5AM", // only 2 digits allowed + "9am-5p m", // space betweem am or pm are not allowed + "9:am-5:30pm", // if there is a : then minutes part must follow! + "9:00am-5:300pm", // Minutes part is limited to 2 digits + "9: 00am-5 :300pm", // No space allowed around the : + }; + check(durations, false); + } + + void check(String[] durations, boolean match) { + for (String aDuration : durations) { + Matcher matcher = p.matcher(aDuration); + if (match) { + assertTrue(aDuration, matcher.matches()); + } else { + assertFalse(aDuration, matcher.matches()); + } + } + } + + @Test + public void test_patterMatching_happyPath_groups() { + // groups returned by matcher are right + String[][] input = new String[][] { + { "9am-5pm", "9", null, "a", "5", null, "p"}, + { "9Am -5 pM", "9", null, "A", "5", null, "p"}, + { "9 AM -5 p.m.", "9", null, "A", "5", null, "p" }, + { "9:30AM - 5:15pm", "9", "30", "A", "5", "15", "p" }, + { "9:30 AM - 5:15 p.m.", "9", "30", "A", "5", "15", "p" }, + }; + checkGroups(input); + } + + void checkGroups(String[][] input) { + for (String[] data : input) { + Matcher m = p.matcher(data[0]); + assertTrue(data[0], m.matches()); + assertEquals(8, m.groupCount()); + assertEquals(data[1], m.group(1)); + assertEquals(data[2], m.group(3)); + assertEquals(data[3], m.group(4)); + assertEquals(data[4], m.group(5)); + assertEquals(data[5], m.group(7)); + assertEquals(data[6], m.group(8)); + } + } + + @Test + public void test_ExtractDuration_happyPath() { + RangerTimeOfDayMatcher matcher = new RangerTimeOfDayMatcher(); + Object[][] input = new Object[][] { + { "9am-5pm", true, 9*60, (12+5)*60 }, + { "1 PM - 10P.M.", true, (12+1)*60, (12+10)*60 }, + { "1PM - 9AM", false, null, null }, // illegal duration should come back as null + { "1PM", false, null, null }, // illegal patterns should come back as null, too + }; + for (Object[] data: input) { + int[] duration = matcher.extractDuration((String)data[0]); + boolean expectedToMatch = (boolean)data[1]; + if (expectedToMatch) { + int start = (Integer)data[2]; + int end = (Integer)data[3]; + assertArrayEquals(new int[] { start, end }, duration); + } else { + assertNull(duration); + } + } + } + + @Test + public void test_durationsMatched() { + List<int[]> durations = Lists.newArrayList( + new int[]{2*60, 7*60}, // 2am-7am + new int[]{9*60, 17*60}); // 9am-5pm + RangerTimeOfDayMatcher matcher = new RangerTimeOfDayMatcher(); + Object[][] input = new Object[][] { + { 1, false }, + { 2, true }, + { 3, true }, + { 7, true }, + { 8, false }, + {9, true }, + {10, true }, + {16, true}, + {17, true}, + {18, false }, + {23, false }, + }; + for (Object[] data : input) { + int hour = (int)data[0]; + boolean matchExpected = (boolean)data[1]; + boolean result = matcher.durationMatched(durations, hour, 0); + if (matchExpected) { + assertTrue("" + hour, result); + } else { + assertFalse("" + hour, result); + } + } + } + + @Test + public void test_end2end_happyPath() { + RangerPolicyItemCondition itemCondition = mock(RangerPolicyItemCondition.class); + when(itemCondition.getValues()).thenReturn(Arrays.asList("2:45a.m. -7:00 AM", " 9:15AM- 5:30P.M. ")); + + RangerTimeOfDayMatcher matcher = new RangerTimeOfDayMatcher(); + matcher.init(null, itemCondition); + + Object[][] input = new Object[][] { + { 1, 0, false }, + { 2, 44, false }, + { 2, 45, true }, + { 3, 0, true }, + { 7, 0, true }, + { 7, 01, false }, + { 8, 0, false }, + { 9, 15, true }, + {10, 0, true }, + {17, 0, true}, + {17, 30, true}, + {17, 31, false}, + {18, 0, false }, + {23, 0, false }, + }; + + RangerAccessRequest request = mock(RangerAccessRequest.class); + for (Object[] data : input) { + int hour = (int)data[0]; + int minute = (int)data[1]; + Calendar c = new GregorianCalendar(2015, Calendar.APRIL, 1, hour, minute); + Date aDate = c.getTime(); + when(request.getAccessTime()).thenReturn(aDate); + boolean matchExpected = (boolean)data[2]; + if (matchExpected) { + assertTrue("" + hour, matcher.isMatched(request)); + } else { + assertFalse("" + hour, matcher.isMatched(request)); + } + } + } +} http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/78889721/agents-common/src/test/resources/log4j.properties ---------------------------------------------------------------------- diff --git a/agents-common/src/test/resources/log4j.properties b/agents-common/src/test/resources/log4j.properties new file mode 100644 index 0000000..12e172b --- /dev/null +++ b/agents-common/src/test/resources/log4j.properties @@ -0,0 +1,36 @@ +# 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. + +##-- To prevent junits from cluttering the build run by default all test runs send output to null appender +log4j.appender.devnull=org.apache.log4j.varia.NullAppender +log4j.rootLogger=FATAL, devnull + +##-- uncomment the following line during during development/debugging so see debug messages during test run to be emitted to console +# ranger.root.logger=WARN,console + +# Define the root logger to the system property "hbase.root.logger". +log4j.rootLogger=${ranger.root.logger} + +# Logging Threshold +log4j.threshold=ALL + +# +# console +# Add "console" to rootlogger above if you want to use this +# +log4j.appender.console=org.apache.log4j.ConsoleAppender +log4j.appender.console.target=System.err +log4j.appender.console.layout=org.apache.log4j.PatternLayout +log4j.appender.console.layout.ConversionPattern=%d{ISO8601} %-5p [%t] %c{2}: %m%n
