访问控制器用法

2022-09-01 11:58:43

我正在尝试了解Java安全性和AccessController.doPrivileged()用法的基础知识,我从一个示例程序开始

import java.security.AccessController;
import java.security.PrivilegedAction;
public class AccessSystemProperty {
   public static void main(String[] args) {
     System.out.println(System.getSecurityManager());
       AccessController.doPrivileged(
        new PrivilegedAction<Boolean>(){
           public Boolean run(){
               System.out.println(System.getProperty("java.home"));
               return Boolean.TRUE;
           }
        }
       );
   }
}

如果我尝试使用默认安全管理运行上面的代码,我得到的是AccessControlException我的stacktrace是

C:\>java -Djava.security.manager AccessSystemProperty
java.lang.SecurityManager@923e30
Exception in thread "main" java.security.AccessControlException: access denied (
java.util.PropertyPermission java.home read)
        at java.security.AccessControlContext.checkPermission(Unknown Source)
        at java.security.AccessController.checkPermission(Unknown Source)
        at java.lang.SecurityManager.checkPermission(Unknown Source)
        at java.lang.SecurityManager.checkPropertyAccess(Unknown Source)
        at java.lang.System.getProperty(Unknown Source)
        at AccessSystemProperty$1.run(AccessSystemProperty.java:9)
        at AccessSystemProperty$1.run(AccessSystemProperty.java:8)
        at java.security.AccessController.doPrivileged(Native Method)
        at AccessSystemProperty.main(AccessSystemProperty.java:6)

请帮助我清楚地了解

1) 当我们需要使用 AccessController.doPrivileged() 时?(如果 SecurityManager 存在,我们使用 AccessController.doPrivileged - 为什么在上面的例子中失败了)

2)通过使用AccessController和PrivilegedAction,我们获得的真正优势是什么?

3)我们是否需要自定义策略文件才能使用上述示例?

谢谢

保罗


答案 1

您可以使用 AccessController.doPrivileged() 为调用堆栈中的代码早期代码提供的某些权限,这些权限是调用堆栈中前面的代码所不具备的,但由于在策略中授予了该权限,因此特权代码确实具有这些特权。

例如,假设 ClassA 调用 ClassB 上的方法,并且 ClassB 需要读取 java.home 系统属性(从您的示例中借用),并假设您已按照您的示例指定了 SecurityManager。

还假设 ClassB 是从名为“classb.jar”的 jar 加载的(但为了使示例正常工作,不会从该 jar 加载 ClassA),安全策略文件中应包含以下内容:

grant codeBase "file:/home/somebody/classb.jar" { 
    permission java.util.PropertyPermission "java.home", "read";
};

现在,当 ClassB 运行并尝试执行 System.getProperty() 时,该系统未包装在 “java.home” 上的 AccessController.doPrivileged() 中。安全管理器将检查堆栈,以查看堆栈上较高的每个类是否具有“java.home”的 PropertyPermission(无论是直接的还是隐含的)。否则,访问将失败。

但是,如果 ClassB 将 System.getProperty() 包装在 AccessController.doPrivileged() 中,则安全管理员只关心策略文件是否为 ClassB 提供了该权限,因此允许访问。

这里有一个片段来展示这一点:

public void doStuff() {

    try {
        /*
         * this will fail even if this class has permission via the policy file
         * IF any caller does not have permission
         */
        System.out.println(System.getProperty("java.home")); 
    } catch (Exception e1) {
        System.out.println(e1.getMessage());
    }
    AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
        public Boolean run() {
            try {
                /*
                 * this will be allowed if this class has permission via the policy
                 * file even if no caller has permission
                 */
                System.out.println(System.getProperty("java.home"));
            } catch (Exception e) {
                System.out.println(e.getMessage());
            }

            return Boolean.TRUE;
        }
    });

因此,在您的示例中,您只需要指定一个策略文件,其中包含类似于我上面引用的授权节的内容。


答案 2