You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@karaf.apache.org by jb...@apache.org on 2013/10/22 05:13:23 UTC
svn commit: r1534467 [2/5] - in /karaf/trunk: ./
assemblies/features/framework/src/main/feature/
assemblies/features/framework/src/main/resources/resources/etc/
itests/src/test/java/org/apache/karaf/itests/
jaas/command/src/main/java/org/apache/karaf/j...
Added: karaf/trunk/service/guard/src/main/java/org/apache/karaf/service/guard/tools/ACLConfigurationParser.java
URL: http://svn.apache.org/viewvc/karaf/trunk/service/guard/src/main/java/org/apache/karaf/service/guard/tools/ACLConfigurationParser.java?rev=1534467&view=auto
==============================================================================
--- karaf/trunk/service/guard/src/main/java/org/apache/karaf/service/guard/tools/ACLConfigurationParser.java (added)
+++ karaf/trunk/service/guard/src/main/java/org/apache/karaf/service/guard/tools/ACLConfigurationParser.java Tue Oct 22 03:13:20 2013
@@ -0,0 +1,334 @@
+/*
+ * 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.karaf.service.guard.tools;
+
+import java.util.*;
+
+public class ACLConfigurationParser {
+
+ // note that the order of the enums is important. Needs to be from most specific to least specific.
+ public enum Specificity {
+ ARGUMENT_MATCH,
+ SIGNATURE_MATCH,
+ NAME_MATCH,
+ WILDCARD_MATCH,
+ NO_MATCH
+ };
+
+ /**
+ * Returns the roles that can invoke the given operation. This is determined by matching the
+ * operation details against configuration provided.<p/>
+ *
+ * The following configuration is supported. Keys are used to match an invocation against. The value can contain
+ * a comma-separated list of roles. Spaces are ignored for the role values. Note that comments are allowed in the
+ * value field after the hash {@code #} character:
+ * <pre>
+ * {@code
+ * myMethod = role1, role2
+ * methodName(int)[/17/] = role1 # regex match, assume it's surrounded by ^ and $
+ * methodName(int)[/[01]8/] = role2
+ * methodName(int)["19"] = role3 # exact value match
+ * methodName(int) = role4 # signature match
+ * methodName(java.lang.String, int) = role5 # signature match
+ * methodName = # no roles can invoke this command
+ * method* = role6 # name prefix/wildcard match. The asterisk must appear at the end.
+ * }
+ * </pre>
+ *
+ * The following algorithm is used to find matching roles:
+ * <ol>
+ * <li>Find all regex and exact value matches. For all parameters these matches are found by calling {@code toString()}
+ * on the parameters passed in. If there are multiple matches in this category all the matching roles are collected.
+ * If any is found return these roles.
+ * </li>
+ * <li>Find a signature match. If found return the associated roles.</li>
+ * <li>Find a method name match. If found return the associated roles.</li>
+ * <li>Find a method name prefix/wildcard match. If more than one prefix match, the roles associated with the longest
+ * prefix is used. So for example, if there are rules for {@code get*} and {@code *} only the roles associated with
+ * {@code get*} are returned.
+ * </li>
+ * <li>If none of the above criteria match, this method returns {@code null}.</li>
+ * </ol>
+ *
+ * @param methodName the method name to be invoked.
+ * @param params the parameters provided for the invocation. May be {@code null} for cases there the parameters are not yet
+ * known. In this case the roles that can <em>potentially</em> invoke the method are returned, although based on
+ * parameter values the actual invocation may still be denied.
+ * @param signature the signature of the method specified as an array of class name. For simple types, the simple type name
+ * is used (e.g. "int").
+ * @param config the configuration to check against.
+ * @param addToRoles the list of roles (which may be empty) if a matching configuration iteam has been found.
+ * @return the specificity
+ */
+ public static Specificity getRolesForInvocation(String methodName, Object[] params, String[] signature,
+ Dictionary<String, Object> config, List<String> addToRoles) {
+ Dictionary<String, Object> properties = trimKeys(config);
+
+ Specificity s = getRolesBasedOnSignature(methodName, params, signature, properties, addToRoles);
+ if (s != Specificity.NO_MATCH) {
+ return s;
+ }
+
+ s = getRolesBasedOnSignature(methodName, params, null, properties, addToRoles);
+ if (s != Specificity.NO_MATCH) {
+ return s;
+ }
+
+ List<String> roles = getMethodNameWildcardRoles(properties, methodName);
+ if (roles != null) {
+ addToRoles.addAll(roles);
+ return Specificity.WILDCARD_MATCH;
+ } else {
+ return Specificity.NO_MATCH;
+ }
+ }
+
+ private static Specificity getRolesBasedOnSignature(String methodName, Object[] params, String[] signature,
+ Dictionary<String, Object> properties, List<String> roles) {
+ if (params != null) {
+ boolean foundExactOrRegex = false;
+ Object exactArgMatchRoles = properties.get(getExactArgSignature(methodName, signature, params));
+ if (exactArgMatchRoles instanceof String) {
+ roles.addAll(parseRoles((String) exactArgMatchRoles));
+ foundExactOrRegex = true;
+ }
+
+ List<String> r = getRegexRoles(properties, methodName, signature, params);
+ if (r != null) {
+ foundExactOrRegex = true;
+ roles.addAll(r);
+ }
+
+ if (foundExactOrRegex) {
+ // since we have the actual parameters we can match them and if they do we won't look for any
+ // more generic rules...
+ return Specificity.ARGUMENT_MATCH;
+ }
+ } else {
+ // this is used in the case where parameters aren't known yet and the system wants to find out
+ // what roles in principle can invoke this method
+ List<String> r = getExactArgOrRegexRoles(properties, methodName, signature);
+ if (r != null) {
+ roles.addAll(r);
+ }
+ }
+
+ Object signatureRoles = properties.get(getSignature(methodName, signature));
+ if (signatureRoles instanceof String) {
+ roles.addAll(parseRoles((String) signatureRoles));
+ return signature == null ? Specificity.NAME_MATCH : Specificity.SIGNATURE_MATCH;
+ }
+
+ return Specificity.NO_MATCH;
+ }
+
+ private static Dictionary<String, Object> trimKeys(Dictionary<String, Object> properties) {
+ Dictionary<String, Object> d = new Hashtable<String, Object>();
+ for (Enumeration<String> e = properties.keys(); e.hasMoreElements(); ) {
+ String key = e.nextElement();
+ Object value = properties.get(key);
+ d.put(removeSpaces(key), value);
+ }
+ return d;
+ }
+
+ private static String removeSpaces(String key) {
+ StringBuilder sb = new StringBuilder();
+ char quoteChar = 0;
+ for (int i = 0; i < key.length(); i++) {
+ char c = key.charAt(i);
+
+ if (quoteChar == 0 && c == ' ')
+ continue;
+
+ if (quoteChar == 0 && (c == '\"' || c == '/') && sb.length() > 0 &&
+ (sb.charAt(sb.length() - 1) == '[' || sb.charAt(sb.length() - 1) == ',')) {
+ // we're in a quoted string
+ quoteChar = c;
+ } else if (quoteChar != 0 && c == quoteChar) {
+ // look ahead to see if the next non-space is the closing bracket or a comma, which ends the quoted string
+ for (int j = i + 1; j < key.length(); j++) {
+ if (key.charAt(j) == ' ')
+ continue;
+ if (key.charAt(j) == ']' || key.charAt(j) == ',')
+ quoteChar = 0;
+ break;
+ }
+ }
+ sb.append(c);
+ }
+ return sb.toString();
+ }
+
+ public static List<String> parseRoles(String roleStr) {
+ int hashIdx = roleStr.indexOf('#');
+ if (hashIdx >= 0) {
+ // you can put a comment at the end
+ roleStr = roleStr.substring(0, hashIdx);
+ }
+
+ List<String> roles = new ArrayList<String>();
+ for (String role : roleStr.split("[,]")) {
+ String trimmed = role.trim();
+ if (trimmed.length() > 0) {
+ roles.add(trimmed);
+ }
+ }
+
+ return roles;
+ }
+
+ private static Object getExactArgSignature(String methodName, String[] signature, Object[] params) {
+ StringBuilder sb = new StringBuilder(getSignature(methodName, signature));
+ sb.append('[');
+ boolean first = true;
+ for (Object param : params) {
+ if (first)
+ first = false;
+ else
+ sb.append(',');
+ sb.append('"');
+ sb.append(param.toString().trim());
+ sb.append('"');
+ }
+ sb.append(']');
+ return sb.toString();
+ }
+
+ private static String getSignature(String methodName, String[] signature) {
+ StringBuilder sb = new StringBuilder(methodName);
+ if (signature == null)
+ return sb.toString();
+
+ sb.append('(');
+ boolean first = true;
+ for (String s : signature) {
+ if (first)
+ first = false;
+ else
+ sb.append(',');
+ sb.append(s);
+ }
+ sb.append(')');
+ return sb.toString();
+ }
+
+ private static List<String> getRegexRoles(Dictionary<String, Object> properties, String methodName, String[] signature, Object[] params) {
+ List<String> roles = new ArrayList<String>();
+ boolean matchFound = false;
+ String methodSig = getSignature(methodName, signature);
+ String prefix = methodSig + "[/";
+ for (Enumeration<String> e = properties.keys(); e.hasMoreElements(); ) {
+ String key = e.nextElement().trim();
+ if (key.startsWith(prefix) && key.endsWith("/]")) {
+ List<String> regexArgs = getRegexDecl(key.substring(methodSig.length()));
+ if (allParamsMatch(regexArgs, params)) {
+ matchFound = true;
+ Object roleStr = properties.get(key);
+ if (roleStr instanceof String) {
+ roles.addAll(parseRoles((String) roleStr));
+ }
+ }
+ }
+ }
+ return matchFound ? roles : null;
+ }
+
+ private static List<String> getExactArgOrRegexRoles(Dictionary<String, Object> properties, String methodName, String[] signature) {
+ List<String> roles = new ArrayList<String>();
+ boolean matchFound = false;
+ String methodSig = getSignature(methodName, signature);
+ String prefix = methodSig + "[";
+ for (Enumeration<String> e = properties.keys(); e.hasMoreElements(); ) {
+ String key = e.nextElement().trim();
+ if (key.startsWith(prefix) && key.endsWith("]")) {
+ matchFound = true;
+ Object roleStr = properties.get(key);
+ if (roleStr instanceof String) {
+ roles.addAll(parseRoles((String) roleStr));
+ }
+ }
+ }
+ return matchFound ? roles : null;
+ }
+
+ private static List<String> getMethodNameWildcardRoles(Dictionary<String, Object> properties, String methodName) {
+ SortedMap<String, String> wildcardRules = new TreeMap<String, String>(new Comparator<String>() {
+ public int compare(String s1, String s2) {
+ // returns longer entries before shorter ones...
+ return s2.length() - s1.length();
+ }
+ });
+ for (Enumeration<String> e = properties.keys(); e.hasMoreElements(); ) {
+ String key = e.nextElement();
+ if (key.endsWith("*")) {
+ String prefix = key.substring(0, key.length() - 1);
+ if (methodName.startsWith(prefix)) {
+ wildcardRules.put(prefix, properties.get(key).toString());
+ }
+ }
+ }
+
+ if (wildcardRules.size() != 0) {
+ return parseRoles(wildcardRules.values().iterator().next());
+ } else {
+ return null;
+ }
+ }
+
+ private static boolean allParamsMatch(List<String> regexArgs, Object[] params) {
+ if (regexArgs.size() != params.length)
+ return false;
+
+ for (int i = 0; i < regexArgs.size(); i++) {
+ if (!params[i].toString().trim().matches(regexArgs.get(i))) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ private static List<String> getRegexDecl(String key) {
+ List<String> l = new ArrayList<String>();
+
+ boolean inRegex = false;
+ StringBuilder curRegex = new StringBuilder();
+ for (int i = 0; i < key.length(); i++) {
+ if (!inRegex) {
+ if (key.length() > i + 1) {
+ String s = key.substring(i, i + 2);
+ if ("[/".equals(s) || ",/".equals(s)) {
+ inRegex = true;
+ i++;
+ continue;
+ }
+ }
+ } else {
+ String s = key.substring(i, i + 2);
+ if ("/]".equals(s) || "/,".equals(s)) {
+ l.add(curRegex.toString());
+ curRegex = new StringBuilder();
+ inRegex = false;
+ continue;
+ }
+ curRegex.append(key.charAt(i));
+ }
+ }
+ return l;
+ }
+}
Added: karaf/trunk/service/guard/src/main/resources/OSGI-INF/bundle.info
URL: http://svn.apache.org/viewvc/karaf/trunk/service/guard/src/main/resources/OSGI-INF/bundle.info?rev=1534467&view=auto
==============================================================================
--- karaf/trunk/service/guard/src/main/resources/OSGI-INF/bundle.info (added)
+++ karaf/trunk/service/guard/src/main/resources/OSGI-INF/bundle.info Tue Oct 22 03:13:20 2013
@@ -0,0 +1,53 @@
+h1. Synopsis
+
+${project.name}
+
+${project.description}
+
+Maven URL:
+ [mvn:${project.groupId}/${project.artifactId}/${project.version}]
+
+h1. Description
+
+Add Role-based access to any OSGi Service
+
+Role-based access is added to existing OSGi services by hiding the
+original service from a clients through service registry hooks and
+presenting a proxy to the service that checks the required roles before
+an invocation is made.
+
+To enable the Role-based access for services, the service needs to match
+the filter in the karaf.secured.services system property (typically set
+in etc/system.properties), e.g:
+
+ karaf.secured.services = (|(objectClass=org.acme*)(foo=bar))
+
+Only services that match this filter have Role-based access applied,
+other services are left alone.
+
+Required roles are registered through the OSGi Configuration Admin
+Service. The service PID must start with org.apache.karaf.service.acl.
+For enabled services configurations with matching PIDs defining a
+service.guard property that matches are looked up.
+Then roles associated with the current method, its signature and/or the
+passed arguments are looked up. For example, take the following
+configuration:
+
+ service.guard = (objectClass=org.acme.MyServiceAPI)
+ myMethod = admin, manager
+
+A special role declaration of '*' means that role checking is disabled
+for this method.
+If a matching ACL is found, but no matching definition for the method
+being invoked can be found, no user can invoke the method.
+If no matching ACL is found, role checking is not enabled for the
+service.
+As with the role-based JMX access, method signatures and arguments
+(either literal or regex-based) can be matched.
+
+When roles are checked, these are obtained from the Subject associated
+with the current AccessControlContext. By default the Karaf
+RolePrincipal is checked for, but other role implementations can be
+supported through the following syntax:
+
+ my.custom.RoleImpl:someRole
\ No newline at end of file
Added: karaf/trunk/service/guard/src/test/java/org/apache/karaf/service/guard/impl/ACLConfigurationParserTest.java
URL: http://svn.apache.org/viewvc/karaf/trunk/service/guard/src/test/java/org/apache/karaf/service/guard/impl/ACLConfigurationParserTest.java?rev=1534467&view=auto
==============================================================================
--- karaf/trunk/service/guard/src/test/java/org/apache/karaf/service/guard/impl/ACLConfigurationParserTest.java (added)
+++ karaf/trunk/service/guard/src/test/java/org/apache/karaf/service/guard/impl/ACLConfigurationParserTest.java Tue Oct 22 03:13:20 2013
@@ -0,0 +1,104 @@
+/*
+ * 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.karaf.service.guard.tools;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Dictionary;
+import java.util.Hashtable;
+import java.util.List;
+
+import org.apache.karaf.service.guard.tools.ACLConfigurationParser.Specificity;
+import org.junit.Test;
+
+public class ACLConfigurationParserTest {
+ @Test
+ public void testParseRoles() {
+ assertEquals(Arrays.asList("some_role"),
+ ACLConfigurationParser.parseRoles(" some_role "));
+ assertEquals(Arrays.asList("a","b","C"),
+ ACLConfigurationParser.parseRoles("a,b,C"));
+ assertEquals(Collections.emptyList(),
+ ACLConfigurationParser.parseRoles("# test comment"));
+ }
+
+ @Test
+ public void testGetRolesForInvocation() {
+ Dictionary<String, Object> config = new Hashtable<String, Object>();
+ config.put("foo", "r1, r2");
+ config.put("bar(java.lang.String, int)[/aa/,/42/]", "ra");
+ config.put("bar(java.lang.String, int)[/bb/,/42/]", "rb");
+ config.put("bar(java.lang.String, int)[\"cc\", \"17\"]", "rc");
+ config.put("bar(java.lang.String, int)", "rd");
+ config.put("bar(java.lang.String)", "re");
+ config.put("bar", "rf");
+ config.put("ba*", "rg #Wildcard");
+
+ List<String> roles1 = new ArrayList<String>();
+ assertEquals(Specificity.NAME_MATCH,
+ ACLConfigurationParser.getRolesForInvocation("foo", new Object [] {}, new String [] {}, config, roles1));
+ assertEquals(Arrays.asList("r1", "r2"), roles1);
+
+ List<String> roles2 = new ArrayList<String>();
+ assertEquals(Specificity.NAME_MATCH,
+ ACLConfigurationParser.getRolesForInvocation("foo", new Object [] {"test"}, new String [] {"java.lang.String"}, config, roles2));
+ assertEquals(Arrays.asList("r1", "r2"), roles2);
+
+ List<String> roles3 = new ArrayList<String>();
+ assertEquals(Specificity.NO_MATCH,
+ ACLConfigurationParser.getRolesForInvocation("test", new Object [] {}, new String [] {}, config, roles3));
+ assertEquals(0, roles3.size());
+
+ List<String> roles4 = new ArrayList<String>();
+ assertEquals(Specificity.ARGUMENT_MATCH,
+ ACLConfigurationParser.getRolesForInvocation("bar", new Object [] {"aa", 42}, new String [] {"java.lang.String", "int"}, config, roles4));
+ assertEquals(Arrays.asList("ra"), roles4);
+
+ List<String> roles5 = new ArrayList<String>();
+ assertEquals(Specificity.ARGUMENT_MATCH,
+ ACLConfigurationParser.getRolesForInvocation("bar", new Object [] {"bb", 42}, new String [] {"java.lang.String", "int"}, config, roles5));
+ assertEquals(Arrays.asList("rb"), roles5);
+
+ List<String> roles6 = new ArrayList<String>();
+ assertEquals(Specificity.ARGUMENT_MATCH,
+ ACLConfigurationParser.getRolesForInvocation("bar", new Object [] {"cc", 17}, new String [] {"java.lang.String", "int"}, config, roles6));
+ assertEquals(Arrays.asList("rc"), roles6);
+
+ List<String> roles7 = new ArrayList<String>();
+ assertEquals(Specificity.SIGNATURE_MATCH,
+ ACLConfigurationParser.getRolesForInvocation("bar", new Object [] {"aaa", 42}, new String [] {"java.lang.String", "int"}, config, roles7));
+ assertEquals(Arrays.asList("rd"), roles7);
+
+ List<String> roles8 = new ArrayList<String>();
+ assertEquals(Specificity.SIGNATURE_MATCH,
+ ACLConfigurationParser.getRolesForInvocation("bar", new Object [] {"aa"}, new String [] {"java.lang.String"}, config, roles8));
+ assertEquals(Arrays.asList("re"), roles8);
+
+ List<String> roles9 = new ArrayList<String>();
+ assertEquals(Specificity.NAME_MATCH,
+ ACLConfigurationParser.getRolesForInvocation("bar", new Object [] {42}, new String [] {"int"}, config, roles9));
+ assertEquals(Arrays.asList("rf"), roles9);
+
+ List<String> roles10 = new ArrayList<String>();
+ assertEquals(Specificity.WILDCARD_MATCH,
+ ACLConfigurationParser.getRolesForInvocation("barr", new Object [] {42}, new String [] {"int"}, config, roles10));
+ assertEquals(Arrays.asList("rg"), roles10);
+ }
+}
Added: karaf/trunk/service/guard/src/test/java/org/apache/karaf/service/guard/impl/ActivatorTest.java
URL: http://svn.apache.org/viewvc/karaf/trunk/service/guard/src/test/java/org/apache/karaf/service/guard/impl/ActivatorTest.java?rev=1534467&view=auto
==============================================================================
--- karaf/trunk/service/guard/src/test/java/org/apache/karaf/service/guard/impl/ActivatorTest.java (added)
+++ karaf/trunk/service/guard/src/test/java/org/apache/karaf/service/guard/impl/ActivatorTest.java Tue Oct 22 03:13:20 2013
@@ -0,0 +1,128 @@
+/*
+ * 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.karaf.service.guard.impl;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
+import org.easymock.EasyMock;
+import org.easymock.IAnswer;
+import org.junit.Test;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Filter;
+import org.osgi.framework.FrameworkUtil;
+import org.osgi.framework.hooks.service.EventListenerHook;
+import org.osgi.framework.hooks.service.FindHook;
+
+import java.util.Dictionary;
+import java.util.Properties;
+
+public class ActivatorTest {
+
+ @SuppressWarnings("unchecked")
+ @Test
+ public void testStartActivator() throws Exception {
+ // keep the old properties. Note that the Properties 'copy constructor' new Properties(props)
+ // doesn't actually copy, hence the awkward setup here...
+ Properties oldProps = new Properties();
+ oldProps.putAll(System.getProperties());
+
+ try {
+ System.setProperty(GuardProxyCatalog.KARAF_SECURED_SERVICES_SYSPROP, "(foo=bar)");
+ Bundle b = EasyMock.createMock(Bundle.class);
+ EasyMock.expect(b.getBundleId()).andReturn(768L).anyTimes();
+ EasyMock.replay(b);
+
+ BundleContext bc = EasyMock.createNiceMock(BundleContext.class);
+ EasyMock.expect(bc.getBundle()).andReturn(b).anyTimes();
+ EasyMock.expect(bc.createFilter(EasyMock.anyObject(String.class))).andAnswer(new IAnswer<Filter>() {
+ @Override
+ public Filter answer() throws Throwable {
+ return FrameworkUtil.createFilter((String) EasyMock.getCurrentArguments()[0]);
+ }
+ }).anyTimes();
+
+ EasyMock.expect(bc.registerService(
+ EasyMock.eq(EventListenerHook.class), EasyMock.isA(EventListenerHook.class), EasyMock.isNull(Dictionary.class)))
+ .andReturn(null);
+ EasyMock.expect(bc.registerService(
+ EasyMock.eq(FindHook.class), EasyMock.isA(FindHook.class), EasyMock.isNull(Dictionary.class)))
+ .andReturn(null);
+
+ EasyMock.replay(bc);
+
+ Activator a = new Activator();
+ a.start(bc);
+
+ assertNotNull(a.guardProxyCatalog);
+ assertNotNull(a.guardingEventHook);
+ assertNotNull(a.guardingFindHook);
+
+ EasyMock.verify(bc);
+ } finally {
+ System.setProperties(oldProps);
+ }
+ }
+
+ @Test
+ public void testStartActivatorNoServicesSecured() throws Exception {
+ // keep the old properties. Note that the Properties 'copy constructor' new Properties(props)
+ // doesn't actually copy, hence the awkward setup here...
+ Properties oldProps = new Properties();
+ oldProps.putAll(System.getProperties());
+
+ try {
+ Properties newProps = removeProperties(System.getProperties(), GuardProxyCatalog.KARAF_SECURED_SERVICES_SYSPROP);
+ System.setProperties(newProps);
+
+ BundleContext bc = EasyMock.createNiceMock(BundleContext.class);
+ EasyMock.replay(bc);
+
+ Activator a = new Activator();
+ a.start(bc);
+
+ assertNull(a.guardProxyCatalog);
+ } finally {
+ System.setProperties(oldProps);
+ }
+ }
+
+ @Test
+ public void testStopActivator() throws Exception {
+ Activator a = new Activator();
+
+ a.guardProxyCatalog = EasyMock.createMock(GuardProxyCatalog.class);
+ a.guardProxyCatalog.close();
+ EasyMock.expectLastCall().once();
+ EasyMock.replay(a.guardProxyCatalog);
+
+ a.stop(EasyMock.createMock(BundleContext.class));
+
+ EasyMock.verify(a.guardProxyCatalog);
+ }
+
+ private Properties removeProperties(Properties props, String ... keys) {
+ Properties p = new Properties();
+ p.putAll(props);
+ for (String key : keys) {
+ p.remove(key);
+ }
+ return p;
+ }
+
+}