SLING-5135 - Whitelist legit usages of loginAdministrative and administrative ResourceResolver
- move LoginAdminWhitelist from o.a.s.jcr.base to o.a.s.jcr.oak-server and do NOT export it
git-svn-id: https://svn.apache.org/repos/asf/sling/trunk@1769105 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/src/main/java/org/apache/sling/jcr/base/LoginAdminWhitelist.java b/src/main/java/org/apache/sling/jcr/base/LoginAdminWhitelist.java
deleted file mode 100644
index 5f1763e..0000000
--- a/src/main/java/org/apache/sling/jcr/base/LoginAdminWhitelist.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * 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.sling.jcr.base;
-
-import org.apache.sling.jcr.api.SlingRepository;
-import org.osgi.annotation.versioning.ProviderType;
-import org.osgi.framework.Bundle;
-
-/**
- * Whitelist that defines which bundles can use the
- * {@link SlingRepository#loginAdministrative} method.
- */
-@ProviderType
-public interface LoginAdminWhitelist {
-
- boolean allowLoginAdministrative(Bundle b);
-}
diff --git a/src/main/java/org/apache/sling/jcr/base/internal/DefaultWhitelist.java b/src/main/java/org/apache/sling/jcr/base/internal/DefaultWhitelist.java
deleted file mode 100644
index 072108d..0000000
--- a/src/main/java/org/apache/sling/jcr/base/internal/DefaultWhitelist.java
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * 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.sling.jcr.base.internal;
-
-/**
- * Define the default whitelist in its own class to better
- * keep track of it. The goal is to reduce it to the bare
- * minimum over time.
- */
-class DefaultWhitelist {
- // TODO: remove bundles as their dependency on admin login is fixed, see SLING-5355 for linked issues
- static final String [] WHITELISTED_BSN = {
- "org.apache.sling.discovery.commons",
- "org.apache.sling.discovery.base",
- "org.apache.sling.discovery.oak",
- "org.apache.sling.extensions.webconsolesecurityprovider",
- "org.apache.sling.i18n",
- "org.apache.sling.installer.provider.jcr",
- "org.apache.sling.jcr.base",
- "org.apache.sling.jcr.contentloader",
- "org.apache.sling.jcr.davex",
- "org.apache.sling.jcr.jackrabbit.usermanager",
- "org.apache.sling.jcr.oak.server",
- "org.apache.sling.jcr.repoinit",
- "org.apache.sling.jcr.resource",
- "org.apache.sling.jcr.webconsole",
- "org.apache.sling.resourceresolver",
- "org.apache.sling.servlets.post", // remove when 2.3.16 is released
- "org.apache.sling.servlets.resolver"
- };
-}
\ No newline at end of file
diff --git a/src/main/java/org/apache/sling/jcr/base/internal/LoginAdminWhitelistImpl.java b/src/main/java/org/apache/sling/jcr/base/internal/LoginAdminWhitelistImpl.java
deleted file mode 100644
index 3d7cafa..0000000
--- a/src/main/java/org/apache/sling/jcr/base/internal/LoginAdminWhitelistImpl.java
+++ /dev/null
@@ -1,144 +0,0 @@
-/*
- * 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.sling.jcr.base.internal;
-
-import java.util.Arrays;
-import java.util.Map;
-import java.util.Set;
-import java.util.TreeSet;
-import java.util.regex.Pattern;
-
-import org.apache.felix.scr.annotations.Component;
-import org.apache.felix.scr.annotations.Property;
-import org.apache.felix.scr.annotations.Service;
-import org.apache.sling.commons.osgi.PropertiesUtil;
-import org.apache.sling.jcr.api.SlingRepository;
-import org.apache.sling.jcr.base.LoginAdminWhitelist;
-import org.osgi.framework.Bundle;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * Whitelist that defines which bundles can use the
- * {@link SlingRepository#loginAdministrative} method.
- *
- * The default configuration lets a few trusted Sling bundles
- * use the loginAdministrative method.
- */
-@Service(value=LoginAdminWhitelist.class)
-@Component(
- label="Apache Sling Login Admin Whitelist",
- description="Defines which bundles can use SlingRepository.loginAdministrative()",
- metatype=true)
-public class LoginAdminWhitelistImpl implements LoginAdminWhitelist {
- private final Logger log = LoggerFactory.getLogger(getClass());
-
- /** Need to allow for bypassing the whitelist, for backwards
- * compatibility with previous Sling versions which didn't
- * implement it. Setting this to true is not recommended
- * and logged as a warning.
- */
- @Property(
- label="Bypass the whitelist",
- description=
- "Allow all bundles to use loginAdministrative(). "
- + "Should ONLY be used for backwards compatibility reasons and "
- + "if you are aware of the related security risks.",
- boolValue=false)
- public static final String PROP_BYPASS_WHITELIST = "whitelist.bypass";
- public static final boolean DEFAULT_BYPASS = false;
- private boolean bypassWhitelist = DEFAULT_BYPASS;
-
- @Property(
- label="Whitelist regexp",
- description="Regular expression for bundle symbolic names for which loginAdministrative() is allowed. "
- + " NOT recommended for production use, but useful for testing with generated bundles.",
- value = "")
- public static final String PROP_WHITELIST_REGEXP = "whitelist.bundles.regexp";
- private Pattern whitelistRegexp;
-
- @Property(
- label="Default whitelisted BSNs",
- description="Default list of bundle symbolic names for which loginAdministrative() is allowed",
- value = {})
- public static final String PROP_DEFAULT_WHITELISTED_BSN = "whitelist.bundles.default";
-
- @Property(
- label="Additional whitelisted BSNs",
- description="Additional list of bundle symbolic names for which loginAdministrative() is allowed",
- value = {})
- public static final String PROP_ADDITIONAL_WHITELISTED_BSN = "whitelist.bundles.additional";
-
- private Set<String> whitelistedBsn;
-
- public void activate(Map<String, Object> config) {
- bypassWhitelist = PropertiesUtil.toBoolean(config.get(PROP_BYPASS_WHITELIST), DEFAULT_BYPASS);
- whitelistedBsn = new TreeSet<String>();
-
- final Object defBsns = config.get(PROP_DEFAULT_WHITELISTED_BSN);
- if(defBsns == null) {
- whitelistedBsn.addAll(Arrays.asList(DefaultWhitelist.WHITELISTED_BSN));
- } else {
- whitelistedBsn.addAll(Arrays.asList(PropertiesUtil.toStringArray(defBsns)));
- }
-
- final Object addBsns = config.get(PROP_ADDITIONAL_WHITELISTED_BSN);
- if(addBsns != null) {
- whitelistedBsn.addAll(Arrays.asList(PropertiesUtil.toStringArray(addBsns)));
- }
-
- final String regexp = PropertiesUtil.toString(config.get(PROP_WHITELIST_REGEXP), "");
- if(regexp.trim().length() > 0) {
- whitelistRegexp = Pattern.compile(regexp);
- log.warn("A {} is configured, this is NOT RECOMMENDED for production: {}", PROP_WHITELIST_REGEXP, whitelistRegexp);
- } else {
- whitelistRegexp = null;
- }
-
- if(bypassWhitelist) {
- log.info("bypassWhitelist={}, whitelisted BSNs=<ALL>", bypassWhitelist);
- log.warn(
- "All bundles are allowed to use loginAdministrative due to the 'bypass whitelist' configuration"
- + " of this service. This is NOT RECOMMENDED, for security reasons."
- );
- } else {
- log.info("bypassWhitelist={}, whitelisted BSNs({})={}",
- new Object[] { bypassWhitelist, whitelistedBsn.size(), whitelistedBsn });
- }
- }
-
- @Override
- public boolean allowLoginAdministrative(Bundle b) {
- if(bypassWhitelist) {
- log.debug("Whitelist is bypassed, all bundles allowed to use loginAdministrative");
- return true;
- }
-
- final String bsn = b.getSymbolicName();
- if(whitelistRegexp != null && whitelistRegexp.matcher(bsn).matches()) {
- log.debug("{} is whitelisted to use loginAdministrative, by regexp", bsn);
- return true;
- } else if(whitelistedBsn.contains(bsn)) {
- log.debug("{} is whitelisted to use loginAdministrative, by explicit whitelist", bsn);
- return true;
- }
- log.debug("{} is not whitelisted to use loginAdministrative", bsn);
- return false;
- }
-}
diff --git a/src/test/java/org/apache/sling/jcr/base/MockLoginAdminWhitelist.java b/src/test/java/org/apache/sling/jcr/base/MockLoginAdminWhitelist.java
deleted file mode 100644
index deb84ff..0000000
--- a/src/test/java/org/apache/sling/jcr/base/MockLoginAdminWhitelist.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * 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.sling.jcr.base;
-
-import org.osgi.framework.Bundle;
-
-/** Mock LoginAdminWhitelist */
-public class MockLoginAdminWhitelist implements LoginAdminWhitelist {
-
- private boolean allowAll;
-
- public MockLoginAdminWhitelist(final boolean allowAll) {
- this.allowAll = allowAll;
- }
-
- @Override
- public boolean allowLoginAdministrative(Bundle b) {
- return allowAll;
- }
-
-}
\ No newline at end of file
diff --git a/src/test/java/org/apache/sling/jcr/base/MockSlingRepositoryManager.java b/src/test/java/org/apache/sling/jcr/base/MockSlingRepositoryManager.java
index 6539905..74b6f91 100644
--- a/src/test/java/org/apache/sling/jcr/base/MockSlingRepositoryManager.java
+++ b/src/test/java/org/apache/sling/jcr/base/MockSlingRepositoryManager.java
@@ -20,8 +20,11 @@
import static org.junit.Assert.fail;
+import java.util.Arrays;
import java.util.Dictionary;
+import java.util.HashSet;
import java.util.Hashtable;
+import java.util.Set;
import javax.jcr.Repository;
import javax.jcr.RepositoryException;
@@ -33,20 +36,25 @@
/** Minimal AbstractSlingRepositoryManager used for testing */
public class MockSlingRepositoryManager extends AbstractSlingRepositoryManager {
- private final Repository repository;
+ public static final String WHITELIST_ALL = "*";
- private LoginAdminWhitelist loginAdminWhitelist;
+ public static final String WHITELIST_NONE = "";
+
+ private final Repository repository;
private boolean loginAdminDisabled;
+ private Set<String> loginAdminWhitelist;
+
public MockSlingRepositoryManager(Repository repository) {
- this(repository, false, new MockLoginAdminWhitelist(true));
+ this(repository, false, WHITELIST_ALL);
}
- public MockSlingRepositoryManager(Repository repository, boolean loginAdminDisabled, LoginAdminWhitelist loginAdminWhitelist) {
+ public MockSlingRepositoryManager(Repository repository, boolean loginAdminDisabled, String... loginAdminWhitelist) {
this.repository = repository;
this.loginAdminDisabled = loginAdminDisabled;
- this.loginAdminWhitelist = loginAdminWhitelist;
+ this.loginAdminWhitelist = new HashSet<>(Arrays.asList(loginAdminWhitelist));
+ this.loginAdminWhitelist.remove(WHITELIST_NONE);
}
@Override
@@ -86,7 +94,7 @@
@Override
protected boolean allowLoginAdministrativeForBundle(final Bundle bundle) {
- return loginAdminWhitelist.allowLoginAdministrative(bundle);
+ return loginAdminWhitelist.contains("*") || loginAdminWhitelist.contains(bundle.getSymbolicName());
}
public void activate(BundleContext context) {
diff --git a/src/test/java/org/apache/sling/jcr/base/internal/LoginAdminWhitelistImplTest.java b/src/test/java/org/apache/sling/jcr/base/internal/LoginAdminWhitelistImplTest.java
deleted file mode 100644
index e621be4..0000000
--- a/src/test/java/org/apache/sling/jcr/base/internal/LoginAdminWhitelistImplTest.java
+++ /dev/null
@@ -1,160 +0,0 @@
-/*
- * 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.sling.jcr.base.internal;
-
-import static org.junit.Assert.assertEquals;
-import static org.mockito.Mockito.when;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.UUID;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.mockito.Mockito;
-import org.osgi.framework.Bundle;
-
-public class LoginAdminWhitelistImplTest {
- private LoginAdminWhitelistImpl whitelist;
- private Map<String, Object> config;
- private static final String TYPICAL_DEFAULT_ALLOWED_BSN = "org.apache.sling.jcr.base";
-
- @Before
- public void setup() {
- whitelist = new LoginAdminWhitelistImpl();
- config = new HashMap<String, Object>();
- }
-
- private void assertAdminLogin(final String bundleSymbolicName, boolean expected) {
- final Bundle b = Mockito.mock(Bundle.class);
- when(b.getSymbolicName()).thenReturn(bundleSymbolicName);
- final boolean actual = whitelist.allowLoginAdministrative(b);
- assertEquals("For bundle " + bundleSymbolicName + ", expected admin login=" + expected, expected, actual);
- }
-
- private List<String> randomBsn() {
- final List<String> result = new ArrayList<String>();
- for(int i=0; i < 5; i++) {
- result.add("random.bsn." + UUID.randomUUID());
- }
- return result;
- }
-
- @Test
- public void testDefaultConfig() {
- whitelist.activate(config);
-
- for(String bsn : DefaultWhitelist.WHITELISTED_BSN) {
- assertAdminLogin(bsn, true);
- }
-
- assertAdminLogin(TYPICAL_DEFAULT_ALLOWED_BSN, true);
-
- for(String bsn : randomBsn()) {
- assertAdminLogin(bsn, false);
- }
- }
-
- @Test
- public void testBypassWhitelist() {
- config.put(LoginAdminWhitelistImpl.PROP_BYPASS_WHITELIST, true);
- whitelist.activate(config);
-
- for(String bsn : randomBsn()) {
- assertAdminLogin(bsn, true);
- }
- }
-
- @Test
- public void testDefaultConfigOnly() {
- final String [] allowed = {
- "bundle1", "bundle2"
- };
- config.put(LoginAdminWhitelistImpl.PROP_DEFAULT_WHITELISTED_BSN, allowed);
- whitelist.activate(config);
-
- assertAdminLogin("bundle1", true);
- assertAdminLogin("bundle2", true);
- assertAdminLogin("foo.1.bar", false);
- assertAdminLogin(TYPICAL_DEFAULT_ALLOWED_BSN, false);
-
- for(String bsn : randomBsn()) {
- assertAdminLogin(bsn, false);
- }
- }
-
- @Test
- public void testAdditionalConfigOnly() {
- final String [] allowed = {
- "bundle5", "bundle6"
- };
- config.put(LoginAdminWhitelistImpl.PROP_ADDITIONAL_WHITELISTED_BSN, allowed);
- whitelist.activate(config);
-
- assertAdminLogin("bundle5", true);
- assertAdminLogin("bundle6", true);
- assertAdminLogin("foo.1.bar", false);
-
- for(String bsn : DefaultWhitelist.WHITELISTED_BSN) {
- assertAdminLogin(bsn, true);
- }
-
- for(String bsn : randomBsn()) {
- assertAdminLogin(bsn, false);
- }
- }
-
- @Test
- public void testDefaultAndAdditionalConfig() {
- config.put(LoginAdminWhitelistImpl.PROP_DEFAULT_WHITELISTED_BSN, new String [] { "defB"});
- config.put(LoginAdminWhitelistImpl.PROP_ADDITIONAL_WHITELISTED_BSN, new String [] { "addB"});
- whitelist.activate(config);
-
- assertAdminLogin("defB", true);
- assertAdminLogin("addB", true);
- assertAdminLogin("foo.1.bar", false);
- assertAdminLogin(TYPICAL_DEFAULT_ALLOWED_BSN, false);
-
- for(String bsn : randomBsn()) {
- assertAdminLogin(bsn, false);
- }
- }
-
- @Test
- public void testRegexpWhitelist() {
- final String [] allowed = {
- "bundle3", "bundle4"
- };
- config.put(LoginAdminWhitelistImpl.PROP_DEFAULT_WHITELISTED_BSN, allowed);
- config.put(LoginAdminWhitelistImpl.PROP_WHITELIST_REGEXP, "foo.*bar");
- whitelist.activate(config);
-
- assertAdminLogin("bundle3", true);
- assertAdminLogin("bundle4", true);
- assertAdminLogin("foo.2.bar", true);
- assertAdminLogin("foo.somethingElse.bar", true);
- assertAdminLogin(TYPICAL_DEFAULT_ALLOWED_BSN, false);
-
- for(String bsn : randomBsn()) {
- assertAdminLogin(bsn, false);
- }
- }
-}
\ No newline at end of file
diff --git a/src/test/java/org/apache/sling/jcr/base/internal/WhitelistWiringTest.java b/src/test/java/org/apache/sling/jcr/base/internal/WhitelistWiringTest.java
index 9822191..dda31d8 100644
--- a/src/test/java/org/apache/sling/jcr/base/internal/WhitelistWiringTest.java
+++ b/src/test/java/org/apache/sling/jcr/base/internal/WhitelistWiringTest.java
@@ -18,6 +18,8 @@
*/
package org.apache.sling.jcr.base.internal;
+import static org.apache.sling.jcr.base.MockSlingRepositoryManager.WHITELIST_ALL;
+import static org.apache.sling.jcr.base.MockSlingRepositoryManager.WHITELIST_NONE;
import static org.junit.Assert.assertEquals;
import java.util.ArrayList;
@@ -30,15 +32,10 @@
import org.apache.sling.jcr.api.SlingRepository;
import org.apache.sling.jcr.base.AbstractSlingRepository2;
-import org.apache.sling.jcr.base.LoginAdminWhitelist;
-import org.apache.sling.jcr.base.MockLoginAdminWhitelist;
import org.apache.sling.jcr.base.MockSlingRepositoryManager;
import org.apache.sling.testing.mock.jcr.MockJcr;
import org.apache.sling.testing.mock.osgi.MockOsgi;
-import org.apache.sling.testing.mock.sling.ResourceResolverType;
-import org.apache.sling.testing.mock.sling.junit.SlingContext;
import org.junit.Before;
-import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@@ -80,7 +77,7 @@
BundleContext bundleContext = MockOsgi.newBundleContext();
Bundle bundle = bundleContext.getBundle();
- LoginAdminWhitelist whitelist = new MockLoginAdminWhitelist(whitelistAllowsLoginAdmin);
+ String whitelist = whitelistAllowsLoginAdmin ? WHITELIST_ALL : WHITELIST_NONE;
final MockSlingRepositoryManager repoMgr =
new MockSlingRepositoryManager(MockJcr.newRepository(), !managerAllowsLoginAdmin, whitelist);