You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@logging.apache.org by gg...@apache.org on 2017/06/23 04:51:33 UTC

logging-log4j2 git commit: [LOG4J2-1699] Configurable Log File Permissions with PosixFilePermission. Apply patch.

Repository: logging-log4j2
Updated Branches:
  refs/heads/master 5b2df230d -> 9d32793b1


[LOG4J2-1699] Configurable Log File Permissions with
PosixFilePermission. Apply patch.

Project: http://git-wip-us.apache.org/repos/asf/logging-log4j2/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-log4j2/commit/9d32793b
Tree: http://git-wip-us.apache.org/repos/asf/logging-log4j2/tree/9d32793b
Diff: http://git-wip-us.apache.org/repos/asf/logging-log4j2/diff/9d32793b

Branch: refs/heads/master
Commit: 9d32793b12e2fe9b7a77519e59f5027942db4917
Parents: 5b2df23
Author: Pierrick HYMBERT <pi...@gmail.com>
Authored: Thu Jun 22 21:51:30 2017 -0700
Committer: Gary Gregory <gg...@apache.org>
Committed: Thu Jun 22 21:51:30 2017 -0700

----------------------------------------------------------------------
 .../rolling/DefaultRolloverStrategy.java        |  20 +-
 .../rolling/DirectWriteRolloverStrategy.java    |  20 +-
 .../action/PosixViewAttributeAction.java        | 216 ++++++++++++----
 .../logging/log4j/core/util/FileUtils.java      |   9 +
 .../appender/FileAppenderPermissionsTest.java   | 211 ++++++++++++++++
 .../FileAppenderPermissionsXmlConfigTest.java   |  66 +++++
 .../core/appender/FilePermissionsTest.java      | 244 -------------------
 ...lingAppenderSizeCompressPermissionsTest.java |   9 +-
 8 files changed, 492 insertions(+), 303 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/9d32793b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/DefaultRolloverStrategy.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/DefaultRolloverStrategy.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/DefaultRolloverStrategy.java
index a91a453..4141195 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/DefaultRolloverStrategy.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/DefaultRolloverStrategy.java
@@ -356,14 +356,18 @@ public class DefaultRolloverStrategy extends AbstractRolloverStrategy {
 
         if (manager.isPosixSupported()) {
             // Propagate posix attribute view to rolled/compressed file
-            Action posixAttributeViewAction = new PosixViewAttributeAction(compressedName,
-                                                                            false,
-                                                                            1,
-                                                                            new PathCondition[0],
-                                                                            getStrSubstitutor(),
-                                                                            manager.getFilePermissions(),
-                                                                            manager.getFileOwner(),
-                                                                            manager.getFileGroup());
+            // @formatter:off
+            Action posixAttributeViewAction = PosixViewAttributeAction.newBuilder()
+                                                        .withBasePath(compressedName)
+                                                        .withFollowLinks(false)
+                                                        .withMaxDepth(1)
+                                                        .withPathConditions(new PathCondition[0])
+                                                        .withSubst(getStrSubstitutor())
+                                                        .withFilePermissions(manager.getFilePermissions())
+                                                        .withFileOwner(manager.getFileOwner())
+                                                        .withFileGroup(manager.getFileGroup())
+                                                        .build();
+            // @formatter:on
             if (compressAction == null) {
                 compressAction = posixAttributeViewAction;
             } else {

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/9d32793b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/DirectWriteRolloverStrategy.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/DirectWriteRolloverStrategy.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/DirectWriteRolloverStrategy.java
index feff516..6ce58d8 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/DirectWriteRolloverStrategy.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/DirectWriteRolloverStrategy.java
@@ -197,14 +197,18 @@ public class DirectWriteRolloverStrategy extends AbstractRolloverStrategy implem
 
         if (manager.isPosixSupported()) {
             // Propagate posix attribute view to rolled/compressed file
-            Action posixAttributeViewAction = new PosixViewAttributeAction(compressedName,
-                                                                            false,
-                                                                            1,
-                                                                            new PathCondition[0],
-                                                                            getStrSubstitutor(),
-                                                                            manager.getFilePermissions(),
-                                                                            manager.getFileOwner(),
-                                                                            manager.getFileGroup());
+            // @formatter:off
+            Action posixAttributeViewAction = PosixViewAttributeAction.newBuilder()
+                                                    .withBasePath(compressedName)
+                                                    .withFollowLinks(false)
+                                                    .withMaxDepth(1)
+                                                    .withPathConditions(new PathCondition[0])
+                                                    .withSubst(getStrSubstitutor())
+                                                    .withFilePermissions(manager.getFilePermissions())
+                                                    .withFileOwner(manager.getFileOwner())
+                                                    .withFileGroup(manager.getFileGroup())
+                                                    .build();
+            // @formatter:on
             if (compressAction == null) {
                 compressAction = posixAttributeViewAction;
             } else {

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/9d32793b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/action/PosixViewAttributeAction.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/action/PosixViewAttributeAction.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/action/PosixViewAttributeAction.java
index 7603e75..d74fcbd 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/action/PosixViewAttributeAction.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/action/PosixViewAttributeAction.java
@@ -32,15 +32,19 @@ import java.util.Set;
 import org.apache.logging.log4j.core.Core;
 import org.apache.logging.log4j.core.config.Configuration;
 import org.apache.logging.log4j.core.config.plugins.Plugin;
-import org.apache.logging.log4j.core.config.plugins.PluginAttribute;
+import org.apache.logging.log4j.core.config.plugins.PluginBuilderAttribute;
+import org.apache.logging.log4j.core.config.plugins.PluginBuilderFactory;
 import org.apache.logging.log4j.core.config.plugins.PluginConfiguration;
 import org.apache.logging.log4j.core.config.plugins.PluginElement;
-import org.apache.logging.log4j.core.config.plugins.PluginFactory;
+import org.apache.logging.log4j.core.config.plugins.validation.constraints.Required;
 import org.apache.logging.log4j.core.lookup.StrSubstitutor;
 import org.apache.logging.log4j.core.util.FileUtils;
+import org.apache.logging.log4j.util.Strings;
 
 /**
- * File posix attribute action.
+ * File posix attribute view action.
+ * 
+ * Allow to define file permissions, user and group for log files on posix supported OS.
  */
 @Plugin(name = "PosixViewAttribute", category = Core.CATEGORY_NAME, printObject = true)
 public class PosixViewAttributeAction extends AbstractPathAction {
@@ -60,19 +64,7 @@ public class PosixViewAttributeAction extends AbstractPathAction {
      */
     private final String fileGroup;
 
-    /**
-     * Constructor of the posix view attribute action.
-     *
-     * @param basePath {@link AbstractPathAction#getBasePath()}
-     * @param followSymbolicLinks {@link AbstractPathAction#isFollowSymbolicLinks()}
-     * @param pathConditions {@link AbstractPathAction#getPathConditions()}
-     * @param subst {@link AbstractPathAction#getStrSubstitutor()}
-     * @param filePermissions Permissions to apply
-     * @param fileOwner File owner
-     * @param fileGroup File group
-     * @param followSymbolicLinks 
-     */
-    public PosixViewAttributeAction(final String basePath, final boolean followSymbolicLinks,
+    private PosixViewAttributeAction(final String basePath, final boolean followSymbolicLinks,
             final int maxDepth, final PathCondition[] pathConditions, final StrSubstitutor subst,
             final Set<PosixFilePermission> filePermissions,
             final String fileOwner, final String fileGroup) {
@@ -82,35 +74,177 @@ public class PosixViewAttributeAction extends AbstractPathAction {
         this.fileGroup = fileGroup;
     }
 
+    @PluginBuilderFactory
+    public static Builder newBuilder() {
+        return new Builder();
+    }
+
     /**
-     * Creates a PosixViewAttributeAction action that defined posix attribute view on a file.
-     * 
-     * @param basePath {@link AbstractPathAction#getBasePath()}
-     * @param followSymbolicLinks {@link AbstractPathAction#isFollowSymbolicLinks()}
-     * @param pathConditions {@link AbstractPathAction#getPathConditions()}
-     * @param subst {@link AbstractPathAction#getStrSubstitutor()}
-     * @param filePermissions File permissions
-     * @param fileOwner File owner
-     * @param fileGroup File group
-     * @return PosixViewAttribute action
+     * Builder for the posix view attribute action.
      */
-    @PluginFactory
-    public static PosixViewAttributeAction createNameCondition(
-            // @formatter:off
-            @PluginAttribute("basePath") final String basePath, //
-            @PluginAttribute(value = "followLinks") final boolean followLinks,
-            @PluginAttribute(value = "maxDepth", defaultInt = 1) final int maxDepth,
-            @PluginElement("PathConditions") final PathCondition[] pathConditions,
-            @PluginAttribute("filePermissions") final String filePermissions,
-            @PluginAttribute("fileOwner") final String fileOwner,
-            @PluginAttribute("fileGroup") final String fileGroup,
-            @PluginConfiguration final Configuration config) {
-            // @formatter:on
-        return new PosixViewAttributeAction(basePath, followLinks, maxDepth,
-                    pathConditions, config.getStrSubstitutor(),
-                    filePermissions != null ? PosixFilePermissions.fromString(filePermissions) : null,
+    public static class Builder implements org.apache.logging.log4j.core.util.Builder<PosixViewAttributeAction> {
+
+        @PluginConfiguration
+        private Configuration configuration;
+        
+        private StrSubstitutor subst;
+
+        @PluginBuilderAttribute
+        @Required(message = "No base path provided")
+        private String basePath;
+
+        @PluginBuilderAttribute
+        private boolean followLinks = false;
+
+        @PluginBuilderAttribute
+        private int maxDepth = 1;
+
+        @PluginElement("PathConditions")
+        private PathCondition[] pathConditions;
+
+        @PluginBuilderAttribute(value = "filePermissions")
+        private String filePermissionsString;
+
+        private Set<PosixFilePermission> filePermissions;
+
+        @PluginBuilderAttribute
+        private String fileOwner;
+
+        @PluginBuilderAttribute
+        private String fileGroup;
+
+        @Override
+        public PosixViewAttributeAction build() {
+            if (Strings.isEmpty(basePath)) {
+                LOGGER.error("Posix file attribute view action not valid because base path is empty.");
+                return null;
+            }
+
+            if (filePermissions == null && Strings.isEmpty(filePermissionsString)
+                        && Strings.isEmpty(fileOwner) && Strings.isEmpty(fileGroup)) {
+                LOGGER.error("Posix file attribute view not valid because nor permissions, user and group defined.");
+                return null;
+            }
+
+            if (!FileUtils.isFilePosixAttributeViewSupported()) {
+                LOGGER.warn("Posix file attribute view defined but it is not supported by this file system.");
+//                return null; // FIXME Should we avoid operations not permitted or unsupported exception ?
+            }
+
+            return new PosixViewAttributeAction(basePath, followLinks, maxDepth, pathConditions,
+                    subst != null ? subst : configuration.getStrSubstitutor(),
+                    filePermissions != null ? filePermissions :
+                                filePermissionsString != null ? PosixFilePermissions.fromString(filePermissionsString) : null,
                     fileOwner,
                     fileGroup);
+        }
+
+        /**
+         * Define required configuration, used to retrieve string substituter.
+         *
+         * @param configuration {@link AbstractPathAction#getStrSubstitutor()}
+         * @return This builder
+         */
+        public Builder withConfiguration(Configuration configuration) {
+            this.configuration = configuration;
+            return this;
+        }
+
+        /**
+         * Define string substituter.
+         *
+         * @param subst {@link AbstractPathAction#getStrSubstitutor()}
+         * @return This builder
+         */
+        public Builder withSubst(StrSubstitutor subst) {
+            this.subst = subst;
+            return this;
+        }
+
+        /**
+         * Define base path to apply condition before execute posix file attribute action.
+         * @param basePath {@link AbstractPathAction#getBasePath()}
+         * @return This builder
+         */
+        public Builder withBasePath(String basePath) {
+            this.basePath = basePath;
+            return this;
+        }
+
+        /**
+         * True to allow synonyms links during search of eligible files.
+         * @param followLinks Follow synonyms links
+         * @return This builder
+         */
+        public Builder withFollowLinks(boolean followLinks) {
+            this.followLinks = followLinks;
+            return this;
+        }
+
+        /**
+         * Define max folder depth to search for eligible files to apply posix attribute view.
+         * @param maxDepth Max search depth 
+         * @return This builder
+         */
+        public Builder withMaxDepth(int maxDepth) {
+            this.maxDepth = maxDepth;
+            return this;
+        }
+
+        /**
+         * Define path conditions to filter files in {@link PosixViewAttributeAction#getBasePath()}.
+         *
+         * @param pathConditions {@link AbstractPathAction#getPathConditions()}
+         * @return This builder
+         */
+        public Builder withPathConditions(PathCondition[] pathConditions) {
+            this.pathConditions = pathConditions;
+            return this;
+        }
+
+        /**
+         * Define file permissions in posix format to apply during action execution eligible files.
+         *
+         * Example:
+         * <p>rw-rw-rw
+         * <p>r--r--r--
+         * @param filePermissionsString Permissions to apply
+         * @return This builder
+         */
+        public Builder withFilePermissionsString(String filePermissionsString) {
+            this.filePermissionsString = filePermissionsString;
+            return this;
+        }
+
+        /**
+         * Define file permissions to apply during action execution eligible files.
+         * @param filePermissions Permissions to apply
+         * @return This builder
+         */
+        public Builder withFilePermissions(Set<PosixFilePermission> filePermissions) {
+            this.filePermissions = filePermissions;
+            return this;
+        }
+
+        /**
+         * Define file owner to apply during action execution eligible files.
+         * @param fileOwner File owner
+         * @return This builder
+         */
+        public Builder withFileOwner(String fileOwner) {
+            this.fileOwner = fileOwner;
+            return this;
+        }
+
+        /**
+         * Define file group to apply during action execution eligible files.
+         * @param fileGroup File group
+         * @return This builder
+         */
+        public Builder withFileGroup(String fileGroup) {
+            this.fileGroup = fileGroup;
+            return this;
+        }
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/9d32793b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/FileUtils.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/FileUtils.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/FileUtils.java
index f82e738..c486d64 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/FileUtils.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/FileUtils.java
@@ -186,4 +186,13 @@ public final class FileUtils {
             }
         }
     }
+
+    /**
+     * Check if posix file attribute view is supported on the default FileSystem.
+     *
+     * @return true if posix file attribute view supported, false otherwise
+     */
+    public static boolean isFilePosixAttributeViewSupported() {
+        return FileSystems.getDefault().supportedFileAttributeViews().contains("posix");
+    }
 }

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/9d32793b/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/FileAppenderPermissionsTest.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/FileAppenderPermissionsTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/FileAppenderPermissionsTest.java
new file mode 100644
index 0000000..ec12e00
--- /dev/null
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/FileAppenderPermissionsTest.java
@@ -0,0 +1,211 @@
+/*
+ * 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.logging.log4j.core.appender;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.nio.charset.Charset;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.attribute.PosixFileAttributes;
+import java.nio.file.attribute.PosixFilePermissions;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+
+import org.apache.logging.log4j.Level;
+import org.apache.logging.log4j.core.Layout;
+import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.core.impl.Log4jLogEvent;
+import org.apache.logging.log4j.core.layout.PatternLayout;
+import org.apache.logging.log4j.core.util.FileUtils;
+import org.apache.logging.log4j.message.SimpleMessage;
+import org.junit.Assert;
+import org.junit.Assume;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+/**
+ * Tests {@link FileAppender}.
+ */
+@RunWith(Parameterized.class)
+public class FileAppenderPermissionsTest {
+
+    private static final String DIR = "target/permissions1";
+
+    @Parameterized.Parameters(name = "{0} {1} {2}")
+    public static Collection<Object[]> data() throws IOException {
+        return Arrays.asList(new Object[][] { //
+              // @formatter:off
+             {"rwxrwxrwx", true, 2},
+             {"rw-r--r--", false, 3},
+             {"rw-------", true, 4},
+             {"rw-rw----", false, 5},
+              });
+              // @formatter:on
+    }
+
+    private final boolean createOnDemand;
+    private final String filePermissions;
+    private final int fileIndex;
+
+    public FileAppenderPermissionsTest(final String filePermissions, final boolean createOnDemand, final int fileIndex) {
+        this.filePermissions = filePermissions;
+        this.createOnDemand = createOnDemand;
+        this.fileIndex = fileIndex;
+    }
+
+    @BeforeClass
+    public static void beforeClass() {
+        Assume.assumeTrue(FileUtils.isFilePosixAttributeViewSupported());
+    }
+
+    @Test
+    public void testFilePermissionsAPI() throws Exception {
+        final File file = new File(DIR, "AppenderTest-" + fileIndex + ".log");
+        final Path path = file.toPath();
+        final Layout<String> layout = PatternLayout.newBuilder().withPattern(PatternLayout.SIMPLE_CONVERSION_PATTERN)
+                .build();
+        // @formatter:off
+        final FileAppender appender = FileAppender.newBuilder()
+            .withFileName(file.getAbsolutePath())
+            .withName("test")
+            .withImmediateFlush(false)
+            .withIgnoreExceptions(false)
+            .withBufferedIo(false)
+            .withBufferSize(1)
+            .withLayout(layout)
+            .withCreateOnDemand(createOnDemand)
+            .withFilePermissions(filePermissions)
+            .build();
+        // @formatter:on
+        try {
+            appender.start();
+            assertTrue("Appender did not start", appender.isStarted());
+            Assert.assertNotEquals(createOnDemand, Files.exists(path));
+            long curLen = file.length();
+            long prevLen = curLen;
+            assertTrue("File length: " + curLen, curLen == 0);
+            for (int i = 0; i < 100; ++i) {
+                final LogEvent event = Log4jLogEvent.newBuilder().setLoggerName("TestLogger") //
+                        .setLoggerFqcn(FileAppenderPermissionsTest.class.getName()).setLevel(Level.INFO) //
+                        .setMessage(new SimpleMessage("Test")).setThreadName(this.getClass().getSimpleName()) //
+                        .setTimeMillis(System.currentTimeMillis()).build();
+                try {
+                    appender.append(event);
+                    curLen = file.length();
+                    assertTrue("File length: " + curLen, curLen > prevLen);
+                    // Give up control long enough for another thread/process to occasionally do something.
+                    Thread.sleep(25);
+                } catch (final Exception ex) {
+                    throw ex;
+                }
+                prevLen = curLen;
+            }
+            assertEquals(filePermissions, PosixFilePermissions.toString(Files.getPosixFilePermissions(path)));
+        } finally {
+            appender.stop();
+        }
+        assertFalse("Appender did not stop", appender.isStarted());
+    }
+    
+    @Test
+    public void testFileUserGroupAPI() throws Exception {
+        final File file = new File(DIR, "AppenderTest-" + (1000 + fileIndex) + ".log");
+        final Path path = file.toPath();
+        String user = findAUser();
+        assertNotNull(user);
+        String group = findAGroup(user);
+        assertNotNull(group);
+
+        final Layout<String> layout = PatternLayout.newBuilder().withPattern(PatternLayout.SIMPLE_CONVERSION_PATTERN)
+                .build();
+        // @formatter:off
+        final FileAppender appender = FileAppender.newBuilder()
+            .withFileName(file.getAbsolutePath())
+            .withName("test")
+            .withImmediateFlush(true)
+            .withIgnoreExceptions(false)
+            .withBufferedIo(false)
+            .withBufferSize(1)
+            .withLayout(layout)
+            .withFilePermissions(filePermissions)
+            .withFileOwner(user)
+            .withFileGroup(group)
+            .build();
+        // @formatter:on
+        try {
+            appender.start();
+            assertTrue("Appender did not start", appender.isStarted());
+            long curLen = file.length();
+            long prevLen = curLen;
+            assertTrue(file + " File length: " + curLen, curLen == 0);
+            for (int i = 0; i < 100; ++i) {
+                final LogEvent event = Log4jLogEvent.newBuilder().setLoggerName("TestLogger") //
+                        .setLoggerFqcn(FileAppenderPermissionsTest.class.getName()).setLevel(Level.INFO) //
+                        .setMessage(new SimpleMessage("Test")).setThreadName(this.getClass().getSimpleName()) //
+                        .setTimeMillis(System.currentTimeMillis()).build();
+                try {
+                    appender.append(event);
+                    curLen = file.length();
+                    assertTrue("File length: " + curLen, curLen > prevLen);
+                    // Give up control long enough for another thread/process to occasionally do something.
+                    Thread.sleep(25);
+                } catch (final Exception ex) {
+                    throw ex;
+                }
+                prevLen = curLen;
+            }
+            assertEquals(filePermissions, PosixFilePermissions.toString(Files.getPosixFilePermissions(path)));
+            assertEquals(user, Files.getOwner(path).getName());
+            assertEquals(group, Files.readAttributes(path, PosixFileAttributes.class).group().getName());
+        } finally {
+            appender.stop();
+        }
+        assertFalse("Appender did not stop", appender.isStarted());
+    }
+
+    public static String findAGroup(String user) throws IOException {
+        String group = user;
+        try (FileInputStream fis = new FileInputStream("/etc/group")) {
+            List<String> groups = org.apache.commons.io.IOUtils.readLines(fis, Charset.defaultCharset());
+            for (int i = 0; i < groups.size(); i++) {
+                String aGroup = groups.get(i);
+                if (!aGroup.startsWith(user) && aGroup.contains(user)) {
+                    group = aGroup.split(":")[0];
+                    break;
+                }
+            }
+        }
+        return group;
+    }
+
+    private static String findAUser() throws IOException {
+        // On jenkins build within ubuntu, it is not possible to chmod to another user
+        return System.getProperty("user.name");
+    }
+
+
+}

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/9d32793b/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/FileAppenderPermissionsXmlConfigTest.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/FileAppenderPermissionsXmlConfigTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/FileAppenderPermissionsXmlConfigTest.java
new file mode 100644
index 0000000..941e785
--- /dev/null
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/FileAppenderPermissionsXmlConfigTest.java
@@ -0,0 +1,66 @@
+/*
+ * 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.logging.log4j.core.appender;
+
+import static org.junit.Assert.assertEquals;
+
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.nio.file.attribute.PosixFilePermissions;
+
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.core.util.FileUtils;
+import org.apache.logging.log4j.junit.LoggerContextRule;
+import org.junit.Assume;
+import org.junit.BeforeClass;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.RuleChain;
+
+/**
+ * Tests {@link FileAppender}.
+ */
+public class FileAppenderPermissionsXmlConfigTest {
+
+    private static final String DIR = "target/permissions1";
+
+    private static final String CONFIG = "log4j-posix.xml";
+
+    public static LoggerContextRule loggerContextRule = LoggerContextRule.createShutdownTimeoutLoggerContextRule(CONFIG);
+
+    @Rule
+    public RuleChain chain = loggerContextRule.withCleanFoldersRule(DIR);
+
+    @BeforeClass
+    public static void beforeClass() {
+        Assume.assumeTrue(FileUtils.isFilePosixAttributeViewSupported());
+    }
+
+    @Test
+    public void testFilePermissions() throws Exception {
+        Logger logger = loggerContextRule.getLogger(FileAppenderPermissionsTest.class);
+        for (int i = 0; i < 1000; ++i) {
+            String message = "This is test message number " + i;
+            logger.debug(message);
+        }
+        assertEquals("rw-------", PosixFilePermissions.toString(
+                    Files.getPosixFilePermissions(Paths.get("target/permissions1/AppenderTest-1.log"))));
+    }
+
+    
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/9d32793b/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/FilePermissionsTest.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/FilePermissionsTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/FilePermissionsTest.java
deleted file mode 100644
index 40c4e7b..0000000
--- a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/FilePermissionsTest.java
+++ /dev/null
@@ -1,244 +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.logging.log4j.core.appender;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.nio.charset.Charset;
-import java.nio.file.FileSystems;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.nio.file.attribute.PosixFileAttributes;
-import java.nio.file.attribute.PosixFilePermissions;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.List;
-
-import org.apache.logging.log4j.Level;
-import org.apache.logging.log4j.Logger;
-import org.apache.logging.log4j.core.Layout;
-import org.apache.logging.log4j.core.LogEvent;
-import org.apache.logging.log4j.core.impl.Log4jLogEvent;
-import org.apache.logging.log4j.core.layout.PatternLayout;
-import org.apache.logging.log4j.junit.LoggerContextRule;
-import org.apache.logging.log4j.message.SimpleMessage;
-import org.junit.Assert;
-import org.junit.Assume;
-import org.junit.BeforeClass;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.RuleChain;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
-
-/**
- * Tests {@link FileAppender}.
- */
-public class FilePermissionsTest {
-
-    private static final String DIR = "target/permissions1";
-
-    @RunWith(Parameterized.class)
-    public static final class TestParameterized {
-
-        @Parameterized.Parameters(name = "{0} {1} {2}")
-        public static Collection<Object[]> data() throws IOException {
-            return Arrays.asList(new Object[][] { //
-                  // @formatter:off
-                 {"rwxrwxrwx", true, 2},
-                 {"rw-r--r--", false, 3},
-                 {"rw-------", true, 4},
-                 {"rw-rw----", false, 5},
-                  });
-                  // @formatter:on
-        }
-
-        private final boolean createOnDemand;
-        private final String filePermissions;
-        private final int fileIndex;
-
-        public TestParameterized(final String filePermissions, final boolean createOnDemand, final int fileIndex) {
-            this.filePermissions = filePermissions;
-            this.createOnDemand = createOnDemand;
-            this.fileIndex = fileIndex;
-        }
-
-        @BeforeClass
-        public static void beforeClass() {
-            Assume.assumeTrue(FileSystems.getDefault().supportedFileAttributeViews().contains("posix"));
-        }
-
-        @Test
-        public void testFilePermissionsAPI() throws Exception {
-            final File file = new File(DIR, "AppenderTest-" + fileIndex + ".log");
-            final Path path = file.toPath();
-            final Layout<String> layout = PatternLayout.newBuilder().withPattern(PatternLayout.SIMPLE_CONVERSION_PATTERN)
-                    .build();
-            // @formatter:off
-            final FileAppender appender = FileAppender.newBuilder()
-                .withFileName(file.getAbsolutePath())
-                .withName("test")
-                .withImmediateFlush(false)
-                .withIgnoreExceptions(false)
-                .withBufferedIo(false)
-                .withBufferSize(1)
-                .withLayout(layout)
-                .withCreateOnDemand(createOnDemand)
-                .withFilePermissions(filePermissions)
-                .build();
-            // @formatter:on
-            try {
-                appender.start();
-                assertTrue("Appender did not start", appender.isStarted());
-                Assert.assertNotEquals(createOnDemand, Files.exists(path));
-                long curLen = file.length();
-                long prevLen = curLen;
-                assertTrue("File length: " + curLen, curLen == 0);
-                for (int i = 0; i < 100; ++i) {
-                    final LogEvent event = Log4jLogEvent.newBuilder().setLoggerName("TestLogger") //
-                            .setLoggerFqcn(FilePermissionsTest.class.getName()).setLevel(Level.INFO) //
-                            .setMessage(new SimpleMessage("Test")).setThreadName(this.getClass().getSimpleName()) //
-                            .setTimeMillis(System.currentTimeMillis()).build();
-                    try {
-                        appender.append(event);
-                        curLen = file.length();
-                        assertTrue("File length: " + curLen, curLen > prevLen);
-                        // Give up control long enough for another thread/process to occasionally do something.
-                        Thread.sleep(25);
-                    } catch (final Exception ex) {
-                        throw ex;
-                    }
-                    prevLen = curLen;
-                }
-                assertEquals(filePermissions, PosixFilePermissions.toString(Files.getPosixFilePermissions(path)));
-            } finally {
-                appender.stop();
-            }
-            assertFalse("Appender did not stop", appender.isStarted());
-        }
-        
-    }
-
-    public static class TestNotParameterized {
-        private static final String CONFIG = "log4j-posix.xml";
-
-        public static LoggerContextRule loggerContextRule = LoggerContextRule.createShutdownTimeoutLoggerContextRule(CONFIG);
-
-        @Rule
-        public RuleChain chain = loggerContextRule.withCleanFoldersRule(DIR);
-
-        @BeforeClass
-        public static void beforeClass() {
-            Assume.assumeTrue(FileSystems.getDefault().supportedFileAttributeViews().contains("posix"));
-        }
-        
-        @Test
-        public void testFilePermissions() throws Exception {
-            Logger logger = loggerContextRule.getLogger(FilePermissionsTest.class);
-            for (int i = 0; i < 1000; ++i) {
-                String message = "This is test message number " + i;
-                logger.debug(message);
-            }
-            assertEquals("rw-------", PosixFilePermissions.toString(
-                        Files.getPosixFilePermissions(Paths.get("target/permissions1/AppenderTest-1.log"))));
-        }
-
-        @Test
-        public void testFileUserGroupAPI() throws Exception {
-            final File file = new File(DIR, "AppenderTest-0.log");
-            final Path path = file.toPath();
-            String user = findAUser();
-            assertNotNull(user);
-            String group = findAGroup(user);
-            assertNotNull(group);
-            String filePermissions = "rw-rw-rw-";
-
-            final Layout<String> layout = PatternLayout.newBuilder().withPattern(PatternLayout.SIMPLE_CONVERSION_PATTERN)
-                    .build();
-            // @formatter:off
-            final FileAppender appender = FileAppender.newBuilder()
-                .withFileName(file.getAbsolutePath())
-                .withName("test")
-                .withImmediateFlush(true)
-                .withIgnoreExceptions(false)
-                .withBufferedIo(false)
-                .withBufferSize(1)
-                .withLayout(layout)
-                .withFilePermissions(filePermissions)
-                .withFileOwner(user)
-                .withFileGroup(group)
-                .build();
-            // @formatter:on
-            try {
-                appender.start();
-                assertTrue("Appender did not start", appender.isStarted());
-                long curLen = file.length();
-                long prevLen = curLen;
-                assertTrue("File length: " + curLen, curLen == 0);
-                for (int i = 0; i < 100; ++i) {
-                    final LogEvent event = Log4jLogEvent.newBuilder().setLoggerName("TestLogger") //
-                            .setLoggerFqcn(FilePermissionsTest.class.getName()).setLevel(Level.INFO) //
-                            .setMessage(new SimpleMessage("Test")).setThreadName(this.getClass().getSimpleName()) //
-                            .setTimeMillis(System.currentTimeMillis()).build();
-                    try {
-                        appender.append(event);
-                        curLen = file.length();
-                        assertTrue("File length: " + curLen, curLen > prevLen);
-                        // Give up control long enough for another thread/process to occasionally do something.
-                        Thread.sleep(25);
-                    } catch (final Exception ex) {
-                        throw ex;
-                    }
-                    prevLen = curLen;
-                }
-                assertEquals(filePermissions, PosixFilePermissions.toString(Files.getPosixFilePermissions(path)));
-                assertEquals(user, Files.getOwner(path).getName());
-                assertEquals(group, Files.readAttributes(path, PosixFileAttributes.class).group().getName());
-            } finally {
-                appender.stop();
-            }
-            assertFalse("Appender did not stop", appender.isStarted());
-        }
-
-        public static String findAGroup(String user) throws IOException {
-            String group = null;
-            try (FileInputStream fis = new FileInputStream("/etc/group")) {
-                List<String> groups = org.apache.commons.io.IOUtils.readLines(fis, Charset.defaultCharset());
-                for (int i = 0; i < groups.size(); i++) {
-                    String aGroup = groups.get(i);
-                    if (!aGroup.startsWith(user) && aGroup.contains(user)) {
-                        group = aGroup.split(":")[0];
-                        break;
-                    }
-                }
-            }
-            return group;
-        }
-
-        private static String findAUser() throws IOException {
-            // On jenkins build within ubuntu, it is not possible to chmod to another user
-            return System.getProperty("user.name");
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/9d32793b/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderSizeCompressPermissionsTest.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderSizeCompressPermissionsTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderSizeCompressPermissionsTest.java
index c57705b..0ea11f7 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderSizeCompressPermissionsTest.java
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingAppenderSizeCompressPermissionsTest.java
@@ -19,15 +19,16 @@ import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 
 import java.io.File;
-import java.nio.file.FileSystems;
 import java.nio.file.Files;
 import java.nio.file.attribute.PosixFilePermissions;
 import java.util.concurrent.TimeUnit;
 
 import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.core.util.FileUtils;
 import org.apache.logging.log4j.junit.LoggerContextRule;
 import org.junit.Assume;
 import org.junit.Before;
+import org.junit.BeforeClass;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.RuleChain;
@@ -49,6 +50,11 @@ public class RollingAppenderSizeCompressPermissionsTest {
 
     private Logger logger;
 
+    @BeforeClass
+    public static void beforeClass() {
+        Assume.assumeTrue(FileUtils.isFilePosixAttributeViewSupported());
+    }
+
     @Before
     public void setUp() throws Exception {
         this.logger = loggerContextRule.getLogger(RollingAppenderSizeCompressPermissionsTest.class.getName());
@@ -56,7 +62,6 @@ public class RollingAppenderSizeCompressPermissionsTest {
 
     @Test
     public void testAppenderCompressPermissions() throws Exception {
-        Assume.assumeTrue(FileSystems.getDefault().supportedFileAttributeViews().contains("posix"));
         for (int i = 0; i < 500; ++i) {
             String message = "This is test message number " + i;
             logger.debug(message);