diff --git a/build.xml b/build.xml
index 3778120edb..74ea9aaed5 100644
--- a/build.xml
+++ b/build.xml
@@ -431,6 +431,7 @@
+
diff --git a/conf/access.properties b/conf/access.properties
index 4e66732f88..479fed6f84 100644
--- a/conf/access.properties
+++ b/conf/access.properties
@@ -13,10 +13,14 @@
# 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.
-#
-# This is a sample access file for SimpleAuthenticator. The format of
+
+# This is a sample access file for SimpleAuthority. The format of
# this file is keyspace=users, where users is a comma delimited list of
# authenticatable users from passwd.properties. This file contains
# potentially sensitive information, keep this in mind when setting its
# mode and ownership.
+#
+# The magical '' property lists users who can modify the
+# list of keyspaces: all users will be able to view the list of keyspaces.
+=jsmith
Keyspace1=jsmith,Elvis Presley,dilbert
diff --git a/src/java/org/apache/cassandra/auth/SimpleAuthority.java b/src/java/org/apache/cassandra/auth/SimpleAuthority.java
index 33af7c919b..b014c45383 100644
--- a/src/java/org/apache/cassandra/auth/SimpleAuthority.java
+++ b/src/java/org/apache/cassandra/auth/SimpleAuthority.java
@@ -31,18 +31,33 @@ import org.apache.cassandra.config.ConfigurationException;
public class SimpleAuthority implements IAuthority
{
public final static String ACCESS_FILENAME_PROPERTY = "access.properties";
+ // magical property for WRITE permissions to the keyspaces list
+ public final static String KEYSPACES_WRITE_PROPERTY = "";
@Override
public EnumSet authorize(AuthenticatedUser user, List resource)
{
- if (resource.size() < 3 || !Resources.ROOT.equals(resource.get(0)) || !Resources.KEYSPACES.equals(resource.get(1)))
- // unable to handle resources in other portions of the hierarchy
+ if (resource.size() < 2 || !Resources.ROOT.equals(resource.get(0)) || !Resources.KEYSPACES.equals(resource.get(1)))
+ // we only know how to handle keyspace authorization
return Permission.NONE;
-
- String keyspace = (String)resource.get(2);
+
+ String keyspace;
+ EnumSet authorized;
+ if (resource.size() < 3)
+ {
+ // authorize the user for the keyspace list using the 'magical' keyspace,
+ // but give them read access by default
+ keyspace = KEYSPACES_WRITE_PROPERTY;
+ authorized = EnumSet.of(Permission.READ);
+ }
+ else
+ {
+ // otherwise, authorize them for the actual keyspace
+ keyspace = (String)resource.get(2);
+ authorized = Permission.NONE;
+ }
String afilename = System.getProperty(ACCESS_FILENAME_PROPERTY);
- EnumSet authorized = Permission.NONE;
try
{
FileInputStream in = new FileInputStream(afilename);
@@ -54,11 +69,9 @@ public class SimpleAuthority implements IAuthority
// given keyspace X, users A B and C can be authorized like this (separate their names with spaces):
// X = A B C
- // note we keep the message here and for other authorization problems exactly the same to prevent attackers
- // from guessing what keyspaces are valid
if (null == props.getProperty(keyspace))
+ // no one is authorized
return authorized;
-
for (String allow : props.getProperty(keyspace).split(","))
if (allow.equals(user.username))
authorized = Permission.ALL;
diff --git a/test/conf/access.properties b/test/conf/access.properties
new file mode 100644
index 0000000000..e6ffd9f21c
--- /dev/null
+++ b/test/conf/access.properties
@@ -0,0 +1,26 @@
+# 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.
+
+# This is a sample access file for SimpleAuthority. The format of
+# this file is keyspace=users, where users is a comma delimited list of
+# authenticatable users from passwd.properties. This file contains
+# potentially sensitive information, keep this in mind when setting its
+# mode and ownership.
+#
+# The magical '' property lists users who can modify the
+# list of keyspaces: all users will be able to view the list of keyspaces.
+=user1
+Keyspace1=user1,user2
diff --git a/test/unit/org/apache/cassandra/auth/SimpleAuthorityTest.java b/test/unit/org/apache/cassandra/auth/SimpleAuthorityTest.java
new file mode 100644
index 0000000000..0660954531
--- /dev/null
+++ b/test/unit/org/apache/cassandra/auth/SimpleAuthorityTest.java
@@ -0,0 +1,73 @@
+/*
+* 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.cassandra.auth;
+
+import java.util.Arrays;
+import java.util.EnumSet;
+import java.util.List;
+
+import org.junit.Before;
+import org.junit.Test;
+import static org.junit.Assert.assertEquals;
+
+public class SimpleAuthorityTest
+{
+ private final SimpleAuthority authority = new SimpleAuthority();
+
+ private final AuthenticatedUser USER1 = new AuthenticatedUser("user1");
+ private final AuthenticatedUser USER2 = new AuthenticatedUser("user2");
+ private final AuthenticatedUser USER3 = new AuthenticatedUser("user3");
+
+ private final List KEYSPACES_RESOURCE = Arrays.asList(Resources.ROOT, Resources.KEYSPACES);
+ private final List KEYSPACE1_RESOURCE = Arrays.asList(Resources.ROOT, Resources.KEYSPACES, "Keyspace1");
+ private final List KEYSPACE2_RESOURCE = Arrays.asList(Resources.ROOT, Resources.KEYSPACES, "Keyspace2");
+
+ @Test
+ public void testValidateConfiguration() throws Exception
+ {
+ authority.validateConfiguration();
+ }
+
+ @Test
+ public void testAuthorizeKeyspace() throws Exception
+ {
+ assertEquals(Permission.ALL, authority.authorize(USER1, KEYSPACE1_RESOURCE));
+ assertEquals(Permission.ALL, authority.authorize(USER2, KEYSPACE1_RESOURCE));
+ assertEquals(Permission.NONE, authority.authorize(USER3, KEYSPACE1_RESOURCE));
+
+ assertEquals("a keyspace not listed in the access file should be inaccessible",
+ Permission.NONE,
+ authority.authorize(USER1, KEYSPACE2_RESOURCE));
+ }
+
+ @Test
+ public void testAuthorizeKeyspaceList() throws Exception
+ {
+ assertEquals("user1 should be able to modify the keyspace list",
+ Permission.ALL,
+ authority.authorize(USER1, KEYSPACES_RESOURCE));
+ assertEquals("user2 should only be able to read the keyspace list",
+ EnumSet.of(Permission.READ),
+ authority.authorize(USER2, KEYSPACES_RESOURCE));
+ assertEquals("user3 should only be able to read the keyspace list",
+ EnumSet.of(Permission.READ),
+ authority.authorize(USER3, KEYSPACES_RESOURCE));
+ }
+}