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

Reply via email to