编程授予权限而不使用策略文件

12
如何在不使用策略文件的情况下以编程方式授予一个 RMI 应用程序 AllPermissions 权限? 更新: 经过一些研究,我编写了这个自定义策略类,并通过Policy.setPolicy(new MyPolicy())进行了安装。
现在我收到以下错误消息:

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();
    }

}
4个回答

14

根据@EJP的建议,我使用-Djava.security.debug=access进行调试,并在策略文件中找到了所有需要的权限:

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

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

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

但因为我不想创建一个策略文件,所以我找到了一种通过扩展java.security.Policy类并在应用程序启动时使用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;
    }

}

从Java8开始,您可以将“implies”简化为“return perms.stream().anyMatch(it->it-implies(p));” - s1m0nw1

2

由于Java将您的

new AllPermission()).newPermissionCollection()

视为不可变对象(为什么要向已允许所有权限的集合中添加权限?),因此Java会尝试向该集合中添加权限,这就是错误消息的来源 - Java尝试将 java.io.FilePermission 添加到您的 AllPermission 中。

相反,请执行以下操作:

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;
    }
}

1
实际上,你的推理有点正确。但并不完全正确:检查AllPermissions的源代码,默认情况下(new AllPermission()).newPermissionCollection()返回一个权限集合,该集合始终返回false。直到您向其中添加AllPermission的实例。 - Adel Boutros
1
这是源代码的链接:http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/security/AllPermission.java#191 - Adel Boutros

1

简短的解决方案

将您更新后的解决方案扩展到:

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

考虑到Policy.getPermissions()必须始终返回一个可变的PermissionCollection。

返回:...如果支持此操作,则返回的权限集必须是新的可变实例,并且必须支持异构权限类型...

这个解决方案已经可以工作,因为它在每次调用Policy.getPermissions(ProtectionDomain)时添加了一个AllPermission对象,该对象引用Policy.getPermissions(CodeSource)

清理解决方案

但是有一种更清晰的解决方案,不会跟踪任何不必要的其他权限,因为AllPermissions已经允许几乎所有事情。
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;
    }
}

1
不要安装SecurityManager。只有在使用代码库功能并且需要一个适当的.policy文件时才需要它。

1
如果您正在使用代码库功能,绝对不要授予AllPermission。您将从另一个来源运行代码。您需要构建一个适当的.policy文件,授予您认为下载的代码应该具有的权限,而没有其他权限。您可以通过-Djava.security.debug=access,failure获得一些帮助来确立这一点。 - user207421
2
@AdelBoutros,你没有选择。没有办法做你想做的事情。无论如何,我建议你的客户会更难接受一个禁用了RMI中所有安全功能的产品,即使可能性很小,这也是幸运的。你应该做的是给客户定义权限的机会,而不是试图回避问题并破坏Java安全模型。 - user207421
目前,我已经创建了自己的 SecurityManager 并覆盖了所有的 checkPermissions 方法并使它们什么都不做。但是我想知道这里有什么风险?(我尝试过谷歌搜索,但没有找到太多信息) - Adel Boutros
@AdelBoutros 风险在于将不受信任的代码运行为可信任的代码。这就是 Java 安全模型的一半所涉及的内容。他们不是无缘无故地把它放在那里的:他们之所以这样做,是因为需要解决一个重大的问题。你需要应对它,而不是像我之前说过的那样破坏它。你正在犯一个重大的产品设计错误。 - user207421
让我们在聊天中继续这个讨论。点击此处进入聊天室 - Adel Boutros
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接