了解AccessController.doPrivileged

时间:2016-05-13 12:24:11

标签: java security

我正在浏览此API,摘自javadoc https://docs.oracle.com/javase/8/docs/technotes/guides/security/doprivileged.html#privileged_code

  

"当调用AccessController.checkPermission方法时   最近的调用者,决定是否允许的基本算法   或否认所请求的访问权限如下:

     
      
  1. 如果调用链中任何调用者的代码没有所请求的权限,则抛出AccessControlException
  2.   
  3. 除非满足以下条件:授予其代码权限的呼叫者已被标记为特权,以及所有各方   随后被这个呼叫者(直接或间接)调用了   说许可。"
  4.   

根据我对上述文档的理解,

  

让我们说frameA(有XYZ) - >调用 frameB(继承XYZ)   权限) - >调用 frameC(继承权限XYZ)。因为   SecurityManager是主线程的常用文件

     

因此,如果frameB想要执行需要权限ABC的代码   然后应该更改策略以授予该权限。但当   我将代码包装在AccessController.doPrivileged中,它不会抛出   SecurtyException。

     

所以我很困惑为什么它表现得像这样,这是因为   包装的代码自动给出"所有权限" ?如果是,请点2   以上是矛盾的,因为它说"一个代码为的调用者   授予上述许可已被标记为特权"

以下是我要测试的内容:

import java.security.*;

public class TestingDoPrivileged {

    static SecurityPermission XYZ = new SecurityPermission("xyz");
    static SecurityPermission ABC = new SecurityPermission("abc");
    static SecurityPermission SET_POLICY = new SecurityPermission("setPolicy");

    public static void main(String[] args) {
        setDummySecurityManager();
        frameA();
    }

    private static void frameA() {
        //set the permission XYZ
        setPolicy(XYZ,SET_POLICY);

        //Here the code/resource frameA  has access to XYZ permission
        //Now call frameB which needs ABC permission for the code to execute.
        frameB();

    }
    private static void frameB() {
        //this will pass as this code has the permission XYZ because the policy is set in frameA with XYZ permission
        System.getSecurityManager().checkPermission(XYZ);
        try {
            // this will fail as this code does not have permission for abc
            System.getSecurityManager().checkPermission(ABC);
        } catch (AccessControlException e) {
            System.out.println("passed");
            //pass
        }
        //As the caller of frameB which is frameA has the permission to XYZ only, the following code should fail,
        // right? But it is passing.
        AccessController.doPrivileged((PrivilegedAction) () -> {
            frameC();
            return null;
        });
    }
    private static void frameC() {
        System.getSecurityManager().checkPermission(ABC);
    }

    private static void setDummySecurityManager() {
        setPolicy(SET_POLICY);
        SecurityManager sm = new SecurityManager();
        System.setSecurityManager(sm);
    }
    private static void setPolicy(Permission... perms) {
        Policy.setPolicy(new Policy() {
            @Override
            public PermissionCollection getPermissions(CodeSource codesource) {
                PermissionCollection pc = new Permissions();
                for (Permission pm : perms)
                    pc.add(pm);
                return pc;
            }
        });
    }
}

1 个答案:

答案 0 :(得分:0)

Java 2安全模型适用于相关堆栈帧的权限的交集。如果任何相关框架(或两个参数doPrivileged)没有权限,则访问控制上下文将不具有该权限。

在示例中,代码仅显示XYZSET_POLICY。在doPrivileged内调用调用框架(类TestingDoPrivileged)和lambda框架不具有ABC权限,因此检查失败。

使用此类代码可能会发现,CodeSource的权限仅查找一次。因此,试图改变它自己的权限的代码可能不会按预期运行。

运行代码,似乎永远不会调用getPermissions。查看Policy的来源会提醒我,ProtectionDomain的{​​{1}}在设置时会获得完全权限。如果安全实现不受信任(通常在递归安全检查时堆栈溢出),则会导致问题。

使用策略文件会更好。那或者玩类加载器。