Author: rgodfrey
Date: Fri Nov 21 23:17:15 2014
New Revision: 1641017

URL: http://svn.apache.org/r1641017
Log:
QPID-6242 : AESFileEncrypterFactory does not work on non-POSIX permissioned 
filesystems

Modified:
    
qpid/trunk/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/encryption/AESKeyFileEncrypterFactory.java
    
qpid/trunk/qpid/java/broker-core/src/test/java/org/apache/qpid/server/security/encryption/AESKeyFileEncrypterFactoryTest.java

Modified: 
qpid/trunk/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/encryption/AESKeyFileEncrypterFactory.java
URL: 
http://svn.apache.org/viewvc/qpid/trunk/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/encryption/AESKeyFileEncrypterFactory.java?rev=1641017&r1=1641016&r2=1641017&view=diff
==============================================================================
--- 
qpid/trunk/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/encryption/AESKeyFileEncrypterFactory.java
 (original)
+++ 
qpid/trunk/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/encryption/AESKeyFileEncrypterFactory.java
 Fri Nov 21 23:17:15 2014
@@ -25,13 +25,10 @@ import java.io.FileInputStream;
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.nio.file.Files;
-import java.nio.file.attribute.PosixFilePermission;
-import java.nio.file.attribute.PosixFilePermissions;
+import java.nio.file.Path;
+import java.nio.file.attribute.*;
 import java.security.NoSuchAlgorithmException;
-import java.util.EnumSet;
-import java.util.LinkedHashMap;
-import java.util.Map;
-import java.util.Set;
+import java.util.*;
 
 import javax.crypto.KeyGenerator;
 import javax.crypto.SecretKey;
@@ -89,18 +86,7 @@ public class AESKeyFileEncrypterFactory 
         }
         try
         {
-            Set<PosixFilePermission> permissions = 
Files.getPosixFilePermissions(file.toPath());
-
-            if (permissions.contains(PosixFilePermission.GROUP_READ)
-                || permissions.contains(PosixFilePermission.OTHERS_READ)
-                || permissions.contains(PosixFilePermission.GROUP_WRITE)
-                || permissions.contains(PosixFilePermission.OTHERS_WRITE))
-            {
-                throw new IllegalArgumentException("Key file '"
-                                                + fileLocation
-                                                + "' has incorrect 
permissions.  Only the owner "
-                                                + "should be able to read or 
write this file.");
-            }
+            checkFilePermissions(fileLocation, file);
             if(Files.size(file.toPath()) != AES_KEY_SIZE_BYTES)
             {
                 throw new IllegalArgumentException("Key file '" + fileLocation 
+ "' contains an incorrect about of data");
@@ -129,17 +115,76 @@ public class AESKeyFileEncrypterFactory 
         }
     }
 
+    private void checkFilePermissions(String fileLocation, File file) throws 
IOException
+    {
+        if(isPosixFileSystem(file))
+        {
+            Set<PosixFilePermission> permissions = 
Files.getPosixFilePermissions(file.toPath());
+
+            if (permissions.contains(PosixFilePermission.GROUP_READ)
+                    || permissions.contains(PosixFilePermission.OTHERS_READ)
+                    || permissions.contains(PosixFilePermission.GROUP_WRITE)
+                    || permissions.contains(PosixFilePermission.OTHERS_WRITE)) 
{
+                throw new IllegalArgumentException("Key file '"
+                        + fileLocation
+                        + "' has incorrect permissions.  Only the owner "
+                        + "should be able to read or write this file.");
+            }
+        }
+        else if(isAclFileSystem(file))
+        {
+            AclFileAttributeView attributeView = 
Files.getFileAttributeView(file.toPath(), AclFileAttributeView.class);
+            ArrayList<AclEntry> acls = new ArrayList<>(attributeView.getAcl());
+            ListIterator<AclEntry> iter = acls.listIterator();
+            UserPrincipal owner = Files.getOwner(file.toPath());
+            while(iter.hasNext())
+            {
+                AclEntry acl = iter.next();
+                if(acl.type() == AclEntryType.ALLOW)
+                {
+                    Set<AclEntryPermission> originalPermissions = 
acl.permissions();
+                    Set<AclEntryPermission> updatedPermissions = 
EnumSet.copyOf(originalPermissions);
+
+
+                    if 
(updatedPermissions.removeAll(EnumSet.of(AclEntryPermission.APPEND_DATA,
+                            AclEntryPermission.EXECUTE,
+                            AclEntryPermission.WRITE_ACL,
+                            AclEntryPermission.WRITE_DATA,
+                            AclEntryPermission.WRITE_OWNER))) {
+                        throw new IllegalArgumentException("Key file '"
+                                + fileLocation
+                                + "' has incorrect permissions.  The file 
should not be modifiable by any user.");
+                    }
+                    if (!owner.equals(acl.principal()) && 
updatedPermissions.removeAll(EnumSet.of(AclEntryPermission.READ_DATA))) {
+                        throw new IllegalArgumentException("Key file '"
+                                + fileLocation
+                                + "' has incorrect permissions.  Only the 
owner should be able to read from the file.");
+                    }
+                }
+            }
+        }
+        else
+        {
+            throw new IllegalArgumentException("Unable to determine a 
mechanism to protect access to the key file on this filesystem");
+        }
+    }
+
+    private boolean isPosixFileSystem(File file) throws IOException
+    {
+        return 
Files.getFileStore(file.toPath().getRoot()).supportsFileAttributeView(PosixFileAttributeView.class);
+    }
+
+    private boolean isAclFileSystem(File file) throws IOException
+    {
+        return 
Files.getFileStore(file.toPath().getRoot()).supportsFileAttributeView(AclFileAttributeView.class);
+    }
+
+
     private void createAndPopulateKeyFile(final File file)
     {
         try
         {
-            Set<PosixFilePermission> ownerOnly = 
EnumSet.of(PosixFilePermission.OWNER_READ,
-                                                            
PosixFilePermission.OWNER_WRITE,
-                                                            
PosixFilePermission.OWNER_EXECUTE);
-            Files.createDirectories(file.getParentFile().toPath(), 
PosixFilePermissions.asFileAttribute(ownerOnly));
-
-            Files.createFile(file.toPath(), 
PosixFilePermissions.asFileAttribute(
-                    EnumSet.of(PosixFilePermission.OWNER_READ, 
PosixFilePermission.OWNER_WRITE)));
+            createEmptyKeyFile(file);
 
             KeyGenerator keyGenerator = 
KeyGenerator.getInstance(AES_ALGORITHM);
             keyGenerator.init(AES_KEY_SIZE_BITS);
@@ -149,7 +194,7 @@ public class AESKeyFileEncrypterFactory 
                 os.write(key.getEncoded());
             }
 
-            Files.setPosixFilePermissions(file.toPath(), 
EnumSet.of(PosixFilePermission.OWNER_READ));
+            makeKeyFileReadOnly(file);
         }
         catch (NoSuchAlgorithmException | IOException e)
         {
@@ -158,6 +203,109 @@ public class AESKeyFileEncrypterFactory 
 
     }
 
+    private void makeKeyFileReadOnly(File file) throws IOException
+    {
+        if(isPosixFileSystem(file))
+        {
+            Files.setPosixFilePermissions(file.toPath(), 
EnumSet.of(PosixFilePermission.OWNER_READ));
+        }
+        else if(isAclFileSystem(file))
+        {
+            AclFileAttributeView attributeView = 
Files.getFileAttributeView(file.toPath(), AclFileAttributeView.class);
+            ArrayList<AclEntry> acls = new ArrayList<>(attributeView.getAcl());
+            ListIterator<AclEntry> iter = acls.listIterator();
+            file.setReadOnly();
+            while(iter.hasNext())
+            {
+                AclEntry acl = iter.next();
+                Set<AclEntryPermission> originalPermissions = 
acl.permissions();
+                Set<AclEntryPermission> updatedPermissions = 
EnumSet.copyOf(originalPermissions);
+
+                
if(updatedPermissions.removeAll(EnumSet.of(AclEntryPermission.APPEND_DATA,
+                                                           
AclEntryPermission.DELETE,
+                                                           
AclEntryPermission.EXECUTE,
+                                                           
AclEntryPermission.WRITE_ACL,
+                                                           
AclEntryPermission.WRITE_DATA,
+                                                           
AclEntryPermission.WRITE_ATTRIBUTES,
+                                                           
AclEntryPermission.WRITE_NAMED_ATTRS,
+                                                           
AclEntryPermission.WRITE_OWNER)))
+                {
+                    AclEntry.Builder builder = AclEntry.newBuilder(acl);
+                    builder.setPermissions(updatedPermissions);
+                    iter.set(builder.build());
+                }
+            }
+            attributeView.setAcl(acls);
+        }
+        else
+        {
+            throw new IllegalArgumentException("Unable to determine a 
mechanism to protect access to the key file on this filesystem");
+        }
+    }
+
+    private void createEmptyKeyFile(File file) throws IOException
+    {
+        final Path parentFilePath = file.getParentFile().toPath();
+
+        if(isPosixFileSystem(file)) {
+            Set<PosixFilePermission> ownerOnly = 
EnumSet.of(PosixFilePermission.OWNER_READ,
+                    PosixFilePermission.OWNER_WRITE,
+                    PosixFilePermission.OWNER_EXECUTE);
+            Files.createDirectories(parentFilePath, 
PosixFilePermissions.asFileAttribute(ownerOnly));
+
+            Files.createFile(file.toPath(), 
PosixFilePermissions.asFileAttribute(
+                    EnumSet.of(PosixFilePermission.OWNER_READ, 
PosixFilePermission.OWNER_WRITE)));
+        }
+        else if(isAclFileSystem(file))
+        {
+            Files.createDirectories(parentFilePath);
+            final UserPrincipal owner = Files.getOwner(parentFilePath);
+            AclFileAttributeView attributeView = 
Files.getFileAttributeView(parentFilePath, AclFileAttributeView.class);
+            List<AclEntry> acls = new ArrayList<>(attributeView.getAcl());
+            Iterator<AclEntry> iter = acls.iterator();
+            while(iter.hasNext())
+            {
+                AclEntry acl = iter.next();
+                if(!owner.equals(acl.principal()))
+                {
+                    iter.remove();
+                }
+            }
+            attributeView.setAcl(acls);
+
+            Files.createFile(file.toPath(), new FileAttribute<List<AclEntry>>()
+            {
+                @Override
+                public String name()
+                {
+                    return "acl:acl";
+                }
+
+                @Override
+                public List<AclEntry> value() {
+                    AclEntry.Builder builder = AclEntry.newBuilder();
+                    builder.setType(AclEntryType.ALLOW);
+                    builder.setPermissions(AclEntryPermission.APPEND_DATA,
+                            AclEntryPermission.DELETE,
+                            AclEntryPermission.READ_ACL,
+                            AclEntryPermission.READ_ATTRIBUTES,
+                            AclEntryPermission.READ_DATA,
+                            AclEntryPermission.READ_NAMED_ATTRS,
+                            AclEntryPermission.WRITE_ACL,
+                            AclEntryPermission.WRITE_ATTRIBUTES,
+                            AclEntryPermission.WRITE_DATA);
+                    builder.setPrincipal(owner);
+                    return Collections.singletonList(builder.build());
+                }
+            });
+
+        }
+        else
+        {
+            throw new IllegalArgumentException("Unable to determine a 
mechanism to protect access to the key file on this filesystem");
+        }
+    }
+
     @Override
     public String getType()
     {

Modified: 
qpid/trunk/qpid/java/broker-core/src/test/java/org/apache/qpid/server/security/encryption/AESKeyFileEncrypterFactoryTest.java
URL: 
http://svn.apache.org/viewvc/qpid/trunk/qpid/java/broker-core/src/test/java/org/apache/qpid/server/security/encryption/AESKeyFileEncrypterFactoryTest.java?rev=1641017&r1=1641016&r2=1641017&view=diff
==============================================================================
--- 
qpid/trunk/qpid/java/broker-core/src/test/java/org/apache/qpid/server/security/encryption/AESKeyFileEncrypterFactoryTest.java
 (original)
+++ 
qpid/trunk/qpid/java/broker-core/src/test/java/org/apache/qpid/server/security/encryption/AESKeyFileEncrypterFactoryTest.java
 Fri Nov 21 23:17:15 2014
@@ -35,6 +35,8 @@ import java.nio.file.Path;
 import java.nio.file.Paths;
 import java.nio.file.SimpleFileVisitor;
 import java.nio.file.attribute.BasicFileAttributes;
+import java.nio.file.attribute.FileAttributeView;
+import java.nio.file.attribute.PosixFileAttributeView;
 import java.nio.file.attribute.PosixFilePermission;
 import java.security.NoSuchAlgorithmException;
 import java.util.Collections;
@@ -87,7 +89,7 @@ public class AESKeyFileEncrypterFactoryT
 
     public void testCreateKeyInDefaultLocation() throws Exception
     {
-        if(isStrongEncryptionEnabled())
+        if(isStrongEncryptionEnabled() && supportsPosixFileAttributes())
         {
             ConfigurationSecretEncrypter encrypter = 
_factory.createEncrypter(_broker);
 
@@ -120,7 +122,7 @@ public class AESKeyFileEncrypterFactoryT
 
     public void testSettingContextKeyLeadsToFileCreation() throws Exception
     {
-        if(isStrongEncryptionEnabled())
+        if(isStrongEncryptionEnabled() && supportsPosixFileAttributes())
         {
             String filename = UUID.randomUUID().toString() + ".key";
             String subdirName = getTestName() + File.separator + "test";
@@ -169,7 +171,7 @@ public class AESKeyFileEncrypterFactoryT
 
     public void testPermissionsAreChecked() throws Exception
     {
-        if(isStrongEncryptionEnabled())
+        if(isStrongEncryptionEnabled() && supportsPosixFileAttributes())
         {
 
             String filename = UUID.randomUUID().toString() + ".key";
@@ -201,7 +203,7 @@ public class AESKeyFileEncrypterFactoryT
 
     public void testInvalidKey() throws Exception
     {
-        if(isStrongEncryptionEnabled())
+        if(isStrongEncryptionEnabled() && supportsPosixFileAttributes())
         {
             String filename = UUID.randomUUID().toString() + ".key";
             String subdirName = getTestName() + File.separator + "test";
@@ -233,6 +235,11 @@ public class AESKeyFileEncrypterFactoryT
         }
     }
 
+    private boolean supportsPosixFileAttributes() throws IOException
+    {
+        return 
Files.getFileStore(_tmpDir).supportsFileAttributeView(PosixFileAttributeView.class);
+    }
+
     @Override
     public void tearDown() throws Exception
     {



---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscr...@qpid.apache.org
For additional commands, e-mail: commits-h...@qpid.apache.org

Reply via email to