12

How to programmatically grant AllPermissions to an RMI application without using policy file?

UPDATE:

After some researching, I have written this custom Policy Class and installed it via Policy.setPolicy(new MyPolicy()).

Now I get the following error:

invalid permission: (java.io.FilePermission \C:\eclipse\plugins\org.eclipse.osgi_3.7.0.v20110613.jar read

class MyPolicy extends Policy {

    @Override
    public PermissionCollection getPermissions(CodeSource codesource) {
        return (new AllPermission()).newPermissionCollection();
    }

}
Adel Boutros
  • 10,205
  • 7
  • 55
  • 89

4 Answers4

14

Based on @EJP's advice, I have debugged using -Djava.security.debug=access and found all the needed permissions in a policy file :

grant { permission java.net.SocketPermission "*:1024-", "connect, resolve"; };

grant { permission java.util.PropertyPermission "*", "read, write"; };

grant { permission java.io.FilePermission "<>", "read"; };

But because I didn't want to create a policy file, I found a way to replicate this programmatically by extending java.security.Policy class and setting the policy at the startup of my application using Policy.setPolicy(new MinimalPolicy());

public class MinimalPolicy extends Policy {

    private static PermissionCollection perms;

    public MinimalPolicy() {
        super();
        if (perms == null) {
            perms = new MyPermissionCollection();
            addPermissions();
        }
    }

    @Override
    public PermissionCollection getPermissions(CodeSource codesource) {
        return perms;
    }

    private void addPermissions() {
        SocketPermission socketPermission = new SocketPermission("*:1024-", "connect, resolve");
        PropertyPermission propertyPermission = new PropertyPermission("*", "read, write");
        FilePermission filePermission = new FilePermission("<<ALL FILES>>", "read");

        perms.add(socketPermission);
        perms.add(propertyPermission);
        perms.add(filePermission);
    }

}

class MyPermissionCollection extends PermissionCollection {

    private static final long serialVersionUID = 614300921365729272L;

    ArrayList<Permission> perms = new ArrayList<Permission>();

    public void add(Permission p) {
        perms.add(p);
    }

    public boolean implies(Permission p) {
        for (Iterator<Permission> i = perms.iterator(); i.hasNext();) {
            if (((Permission) i.next()).implies(p)) {
                return true;
            }
        }
        return false;
    }

    public Enumeration<Permission> elements() {
        return Collections.enumeration(perms);
    }

    public boolean isReadOnly() {
        return false;
    }

}
Adel Boutros
  • 10,205
  • 7
  • 55
  • 89
  • As of Java8 you could simplify `implies` to `return perms.stream().anyMatch(it->it-implies(p));` – s1m0nw1 Apr 18 '18 at 06:48
2

Because your

new AllPermission()).newPermissionCollection()

is treated by Java as immutable (why add permissions to a collection that already allows all permissions?), and because Java will try to add permissions to the collection. That's where the error message comes from - Java tried to add a java.io.FilePermission to your AllPermission.

Instead, do this:

class MyPolicy extends Policy {
    @Override
    public PermissionCollection getPermissions(CodeSource codesource) {
        Permissions p = new Permissions();
        p.add(new PropertyPermission("java.class.path", "read"));
        p.add(new FilePermission("/home/.../classes/*", "read"));
        ... etc ...
        return p;
    }
}
WellINever
  • 31
  • 3
  • 1
    Actually your reasoning is kinda on the right track. But it's not entirely true: Checking the source code of AllPermissions, by default the `(new AllPermission()).newPermissionCollection()` returns a collection of permission which will always return false. This is until you add an instance of AllPermission to it. – Adel Boutros Oct 22 '14 at 10:19
  • 1
    Here is the link for the source code: http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/security/AllPermission.java#191 – Adel Boutros Oct 22 '14 at 10:20
1

Don't install the SecurityManager. You only need it if you're using the codebase feature, and if you need that you need a proper .policy file,

user207421
  • 305,947
  • 44
  • 307
  • 483
  • I have to use the codebase feature. So I do need it. I was hoping to replace the policy file with something like a custom `java.security.Policy` which contains a `AllPermissionCollection`. Can it work this way? and what need to be overriden to make it work? – Adel Boutros Jul 31 '12 at 13:10
  • 1
    @AdelBoutros If you're using the codebase feature you definitely don't want to grant AllPermission. You will be running code from anothe source. You need to construct a proper .policy file that grants exactly the permissions you think the downloaded code should need, and no others. You can establish that with a bit of helpmfr from -Djava.security.debug=access,failure. – user207421 Jul 31 '12 at 22:52
  • I already know how to create a policy file. That's not what I want because my application is an **Eclipse plugin**, thus you cannot add a policy file to a single eclipse-plugin, you need to add it to `eclipse.ini` which the clients will find hard to accept – Adel Boutros Aug 01 '12 at 07:57
  • 2
    @AdelBoutros You don't have the choice. There is no way to do what you want. In any case, I suggest that your clients would find it even harder to accept an RMI product that disables all the security features designed into RMI, if it was possible, which fortunately it isn't. What you should be doing is giving the *client* the opportunity to define the permissions, instead of trying to evade the issue and break the Java security model. – user207421 Aug 01 '12 at 08:52
  • At the moment, I have created my own `SecurityManager` and overriden all the `checkPermissions` methods and made them do nothing. But I was wondering what are the risks here? (I tried googling, but didn't find much info) – Adel Boutros Aug 01 '12 at 09:21
  • @AdelBoutros The risks are those associated with running untrusted code as though it was trusted. That's what half the Java Security Model is about. They didn't put it in there fore nothing: they put it in because there is a major major problem to be addressed. You need to grapple with it, not subvert it, as I said before. You are making a major product design error. – user207421 Aug 01 '12 at 10:15
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/14740/discussion-between-adel-boutros-and-ejp) – Adel Boutros Aug 01 '12 at 12:22
1

Short solution

Extend your updated solution to:

public class MyPolicy extends Policy
{
    @Override
    public PermissionCollection getPermissions(CodeSource codesource)
    {
        Permissions p = new Permissions();
        p.add(new AllPermission());
        return p;
    }
}

Consider, that Policy.getPermissions() must always return a mutable PermissionCollection

Returns: ...If this operation is supported, the returned set of permissions must be a new mutable instance and it must support heterogeneous Permission types...

This solution works already, since it adds an AllPermission object into every call of the Policy.getPermissions(ProtectionDomain), that refers to Policy.getPermissions(CodeSource).

Clean solution

But there is a cleaner solution, that doesn't track any unnecessary other Permissions, since AllPermissions allows pretty everything already.

public class MyPolicy extends Policy
{
    private static class AllPermissionsSingleton extends PermissionCollection
    {
        private static final long serialVersionUID = 1L;
        private static final Vector<Permission> ALL_PERMISSIONS_VECTOR = new Vector<Permission>(Arrays.asList(new AllPermission()));

        @Override
        public void add(Permission permission)
        {
        }

        @Override
        public boolean implies(Permission permission)
        {
            return true;
        }

        @Override
        public Enumeration<Permission> elements()
        {
            return ALL_PERMISSIONS_VECTOR.elements();
        }

        @Override
        public boolean isReadOnly()
        {
            return false;
        }
    }

    private static final AllPermissionsSingleton ALL_PERMISSIONS_SINGLETON = new AllPermissionsSingleton();

    @Override
    public PermissionCollection getPermissions(CodeSource codesource)
    {
        return ALL_PERMISSIONS_SINGLETON;
    }
}
Adam Taras
  • 1,403
  • 1
  • 13
  • 15