22

Problem:
In my Java application (not an applet) I wish to limit certain file operations to all classes except a list/group/package of classes that should not be restricted.

Specifically, I would like to limit...

  • File reads
  • File writes
  • File creation
  • File deletion

...such that they can only be done within the current working directory for all but the unrestricted classes.

SecurityManager attempt:
I have tried to implement a subclass of the SecurityManager class that implements this behaviour, however it seems that when checks are made the file information provided does not give more than just the filename (unless I am missing something?).

Also, I don't quite understand how in this case I could find out the class which the call is being made from, to allow me to determine whether to allow the operation or throw an exception. Is there any way I could get all the information I need for this approach to work?

Policy-based attempt:
I am also aware that Java policies are intended for restricting the actions of classes, including things such as file operations. However, I've really struggled to find a good resource to learn how I could go about solving my problems using a .policy file.

Summarisation of question:

1) Are there any alternative approaches that may be preferable to those I've mentioned?

2) Is this possible using a SecurityManager? Am I missing out on how I should actually be implementing such an approach?

3) Is this possible using a policy file? Are there any good resources I've missed on this front?

I'm really not adversed to any amount of hard work I need to invest in achieving this- I'm just unsure as to how I should approach it properly. I'm also sorely lacking in good resources to teach me enough about the two possible approaches I've mentioned, to allow me to implement it myself. Above all, I'm not afraid of significant reading where required!

Thanks for any help you can give, in advance.

obfuscation
  • 1,023
  • 2
  • 16
  • 22

1 Answers1

16

Here is how you can do it using a policy file.

Create a Java file that can act with privileges:

package egPriv;

import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;
import java.security.AccessController;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;

public class PrivCat {
    /** Cat a file with no privileges */
    public void cat(String file) throws IOException {
        cat(new FileReader(file));
    }

    private void cat(Reader r) throws IOException {
        int c;
        while( (c = r.read()) != -1 ) {
            System.out.print((char) c);
        }
        r.close();
    }

    /** Cat a file WITH privileges */
    public void catPriv(final String file) throws IOException {
        Reader r;
        try {
            r = AccessController.doPrivileged(new PrivilegedExceptionAction<Reader>() {
                public Reader run() throws IOException {
                    return new FileReader(file);
                }
            });
        } catch (PrivilegedActionException e) {
            throw (IOException) e.getCause();
        }
        cat(r);
    }
}

Create a regular file for demonstating

package eg;

import egPriv.PrivCat;

import java.io.IOException;

public class Cat extends PrivCat {
    public static void main(String[] args) throws IOException {
        Cat eg2 = new Cat();
        System.out.println("Processing with privilege:");
        eg2.catPriv(args[0]);

        System.out.println("Processing normally");
        eg2.cat(args[0]);
    }
}

Create sample.policy file:

/* anyone can read write and execute within current working dir */
grant {
  permission java.io.FilePermission "${user.dir}", "read,write,execute";
};

grant {
  permission java.io.FilePermission "${user.dir}/*", "read,write,execute,delete";
};


/* Only code from this jar can work outside of CWD */
grant codebase "file:egPriv.jar" {
  permission java.io.FilePermission "<<ALL FILES>>", "read,write,execute,delete";
};

Compile and then Test:

jar cvf egPriv.jar egPriv
jar cvf eg.jar eg


echo 'Restricted' > ..\file.txt
java -cp eg.jar;egPriv.jar -Djava.security.manager -Djava.security.policy=sample.policy  eg.Cat ..\file.txt

echo 'Open' > file.txt
java -cp eg.jar;egPriv.jar -Djava.security.manager -Djava.security.policy=sample.policy  eg.Cat file.txt
Simon G.
  • 6,269
  • 22
  • 29
  • 5
    if you add `-Djava.security.debug=All` to the command line, the output can be quite helpful in working out why your policy file is not working – Simon G. Apr 03 '11 at 01:28
  • Firstly, thanks very much, I'm testing out this implementation right now. Secondly, another quick question- can this co-exist with a SecurityManager that implements some other protection needs I have? – obfuscation Apr 03 '11 at 11:06
  • 1
    The SecurityManager is consulted first and policies only if the security manager does so. The default SecurityManager delegates on to the Perimissions in the policies for everything. If you subclass SecurityManager to do something else for some kind of check, then permissions will not be able to grant the required privilege for that check. – Simon G. Apr 03 '11 at 14:26
  • 1
    For example, if you want to prevent code from changing the current working directory by setting the `${user.dir}` system property and hence working around the privilegs, you could override the SecurityManager.checkPropertyAccess method to always throw a SecurityException, then no amount of privileges and properties will allow code to set a property. – Simon G. Apr 03 '11 at 14:26