diff --git a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/UserAccessControlProvider.java b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/UserAccessControlProvider.java index 889099d..990f878 100644 --- a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/UserAccessControlProvider.java +++ b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/UserAccessControlProvider.java @@ -25,10 +25,12 @@ import org.apache.jackrabbit.core.SessionImpl; import org.apache.jackrabbit.core.id.ItemId; import org.apache.jackrabbit.core.nodetype.NodeTypeImpl; import org.apache.jackrabbit.core.observation.SynchronousEventListener; +import org.apache.jackrabbit.core.security.AnonymousPrincipal; import org.apache.jackrabbit.core.security.SecurityConstants; import org.apache.jackrabbit.core.security.authorization.AbstractAccessControlProvider; import org.apache.jackrabbit.core.security.authorization.AbstractCompiledPermissions; import org.apache.jackrabbit.core.security.authorization.AccessControlEditor; +import org.apache.jackrabbit.core.security.authorization.AccessControlUtils; import org.apache.jackrabbit.core.security.authorization.CompiledPermissions; import org.apache.jackrabbit.core.security.authorization.NamedAccessControlPolicyImpl; import org.apache.jackrabbit.core.security.authorization.Permission; @@ -88,6 +90,17 @@ public class UserAccessControlProvider extends AbstractAccessControlProvider implements UserConstants { private static Logger log = LoggerFactory.getLogger(UserAccessControlProvider.class); + + /** + * Constant for the name of the configuration option "anonymousId". + * The option is a flag indicating the name of the anonymous user id. + */ + public static final String PARAM_ANONYMOUS_ID = "anonymousId"; + + /** + * Constant for the name of the configuration option "anonymousAccess". + */ + public static final String PARAM_ANONYMOUS_ACCESS = "anonymousAccess"; private final AccessControlPolicy policy; @@ -101,6 +114,10 @@ public class UserAccessControlProvider extends AbstractAccessControlProvider private String groupAdminGroupPath; private String administratorsGroupPath; private boolean membersInProperty; + + private String anonymousId; + + private boolean anonymousAccess; /** * @@ -164,6 +181,16 @@ public class UserAccessControlProvider extends AbstractAccessControlProvider membersInProperty = (!(uMgr instanceof UserManagerImpl)) || ((UserManagerImpl) uMgr).getGroupMembershipSplitSize() <= 0; + if (configuration.containsKey(PARAM_ANONYMOUS_ID)) { + anonymousId = (String) configuration.get(PARAM_ANONYMOUS_ID); + } else { + anonymousId = SecurityConstants.ANONYMOUS_ID; + } + + if (configuration.containsKey(PARAM_ANONYMOUS_ACCESS)) { + anonymousAccess = Boolean.parseBoolean((String) configuration.get(PARAM_ANONYMOUS_ACCESS)); + } + } else { throw new RepositoryException("SessionImpl (system session) expected."); } @@ -205,6 +232,10 @@ public class UserAccessControlProvider extends AbstractAccessControlProvider if (isAdminOrSystem(principals)) { return getAdminPermissions(); } else { + if (!anonymousAccess && isAnonymous(principals)) { + return CompiledPermissions.NO_PERMISSION; + } + // determined the 'user' present in the given set of principals. ItemBasedPrincipal userPrincipal = getUserPrincipal(principals); NodeImpl userNode = getUserNode(userPrincipal); @@ -223,6 +254,9 @@ public class UserAccessControlProvider extends AbstractAccessControlProvider */ public boolean canAccessRoot(Set principals) throws RepositoryException { checkInitialized(); + if (!anonymousAccess && isAnonymous(principals)) { + return false; + } return true; } @@ -314,6 +348,17 @@ public class UserAccessControlProvider extends AbstractAccessControlProvider return null; } + private boolean isAnonymous(Set principals) { + for (Principal p : principals) { + if (p instanceof AnonymousPrincipal) { + return true; + } else if (p.getName().equals(anonymousId)) { + return true; + } + } + return false; + } + //--------------------------------------------------------< inner class >--- /** * diff --git a/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/security/user/AnonUserAccessControlProviderTest.java b/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/security/user/AnonUserAccessControlProviderTest.java new file mode 100644 index 0000000..e4045cf --- /dev/null +++ b/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/security/user/AnonUserAccessControlProviderTest.java @@ -0,0 +1,78 @@ +/* + * 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.jackrabbit.core.security.user; + +import java.io.File; +import java.io.FileOutputStream; + +import javax.jcr.LoginException; +import javax.jcr.RepositoryException; +import javax.jcr.Session; +import javax.jcr.SimpleCredentials; +import javax.jcr.security.AccessControlManager; +import javax.jcr.security.AccessControlPolicy; +import javax.jcr.security.AccessControlPolicyIterator; +import javax.jcr.security.Privilege; + +import junit.framework.TestCase; + +import org.apache.commons.io.FileUtils; +import org.apache.commons.io.IOUtils; +import org.apache.jackrabbit.core.TransientRepository; + +public class AnonUserAccessControlProviderTest extends TestCase { + private TransientRepository repository; + + @Override + protected void setUp() throws Exception { + File repoHome = new File("target/repository"); + if (repoHome.exists()) { + FileUtils.deleteQuietly(repoHome); + } + + repoHome.mkdirs(); + File securityWorkspaceDir = new File(repoHome, "workspaces/security"); + securityWorkspaceDir.mkdirs(); + FileUtils.copyFile(new File("src/test/resources/workspace-security.xml"), + new File(securityWorkspaceDir, "workspace.xml")); + repository = new TransientRepository(new File("src/test/resources/repository-security.xml"), repoHome); + } + + @Override + protected void tearDown() throws Exception { + repository.shutdown(); + } + + public void test() throws RepositoryException { + Session session = repository.login(new SimpleCredentials("admin", "admin".toCharArray()), "security"); + + AccessControlManager acm = session.getAccessControlManager(); + + Privilege[] privledges = acm.getPrivileges("/"); + assertEquals(1, privledges.length); + assertEquals("jcr:all", privledges[0].getName()); + session.logout(); + + try { + session = repository.login("security"); + fail("Should not be able to log into the security workspace as the anonymous user"); + } catch (LoginException e) { + } + + session.logout(); + } +} diff --git a/jackrabbit-core/src/test/resources/repository-security.xml b/jackrabbit-core/src/test/resources/repository-security.xml new file mode 100644 index 0000000..7df6bfa --- /dev/null +++ b/jackrabbit-core/src/test/resources/repository-security.xml @@ -0,0 +1,145 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/jackrabbit-core/src/test/resources/workspace-security.xml b/jackrabbit-core/src/test/resources/workspace-security.xml new file mode 100644 index 0000000..3f52170 --- /dev/null +++ b/jackrabbit-core/src/test/resources/workspace-security.xml @@ -0,0 +1,49 @@ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file