SecureTempFileHelper.java

package com.wilzwert.myjobs.infrastructure.storage;


import org.springframework.stereotype.Component;

import java.io.IOException;
import java.nio.file.FileSystems;
import java.nio.file.attribute.*;
import java.util.Collection;
import java.util.Collections;
import java.util.EnumSet;
import java.util.List;

/**
 * @author Wilhelm Zwertvaegher
 * Helper for temp files creation
 * Temp files are by default world readable, as they are created in a common temp dir
 * To secure those files we need to make them readable and writable only by the current system user
 * It is pretty easy when the project is run on posix compatible systems (e.g. Linux)
 * but it gets a bit more complicated on Windows systems
 * The getFileAttribute generates a FileAttribute based on posix support
 */
@Component
public class SecureTempFileHelper {

    private final boolean supportsPosix;

    public SecureTempFileHelper() {
        supportsPosix = FileSystems.getDefault().supportedFileAttributeViews().contains("posix");
    }

    public boolean supportsPosix() {
        return supportsPosix;
    }

    /**
     * Creates a FileAttribute to be passed in the temp file creation
     * based on posix support
     * At this time we have no choice but to use wildcard generics in the method return type because return types
     * differ whether system is posix compatible of not
     * @return a FileAttribute for a temp file
     * @throws IOException en exception FileAttribute cannot be created
     */
    public FileAttribute<? extends Collection<?>> getFileAttribute() throws IOException {
        if(supportsPosix) {
            return PosixFilePermissions
                    .asFileAttribute(PosixFilePermissions.fromString("rwx------"));
        }
        else {
            UserPrincipal user =
                    FileSystems.getDefault()
                            .getUserPrincipalLookupService()
                            .lookupPrincipalByName(System.getProperty("user.name"));
            List<AclEntry> acl =
                    Collections.singletonList(AclEntry.newBuilder()
                            .setType(AclEntryType.ALLOW)
                            .setPrincipal(user)
                            .setPermissions(EnumSet.allOf(AclEntryPermission.class))
                            .setFlags(AclEntryFlag.DIRECTORY_INHERIT, AclEntryFlag.FILE_INHERIT)
                            .build());
            return
                    new FileAttribute<List<AclEntry>>() {
                        @Override
                        public String name() {
                            return "acl:acl";
                        }

                        @Override
                        public List<AclEntry> value() {
                            return acl;
                        }
                    };
        }
    }
}