关于SecurityManager的细节本文章不做介绍,主要聚集在场景搭建以及核心流程的代码跟踪,理解其设计思路。
主要验证System.getSecurityManager().checkSecurityAccess(“a.b.c”)的三个场景:
- 与MainClass在同一个module
- 与MainClass在不同的module
- 在另一个jar包中
分别新增A、B、C、SecurityManagerTest四个类:
A、B、C三个类的代码是一样的,仅是输出的日志为了区分会有调整,代码如下:
security.policy内容如下:
SecurityManagerTest类代码:
在debug SecurityManagerTest类时,添加jvm参数:
-Djava.security.manager -Djava.security.policy=/Users/saleson/IdeaProjects/learn/learn-main/src/main/java/com/saleson/learn/java/security/security.policy
全部正常执行
运行 SecurityManagerTest类,全部正常执行完成,输出如下:
grant1 注释掉
运行 SecurityManagerTest类,在执行A.print()时会抛错,输出如下:
A.print()无法执行;
grant1 和 A.print() 注释掉
把SecurityManagerTest类中的代码调整下:
运行 SecurityManagerTest类,在执行A.print()时会抛错,输出如下:
将SecurityManagerTest的代码再调整下,print() 改为 print(false), 仍能正常执行:
运行 SecurityManagerTest类,输出如下:
为啥能正常执行了呢,这是因为AccessController.doPrivileged(),再重新看下B.print()方法:
后面的节章会从代码debug的视角对比有无使用AccessController.doPrivileged()的区别。
grant2 和 grant3 注释掉之后执行结果类似。
- codeSource
代码源,该对象是由ClassLoader生成,ClassLoader读取class和jar包得知类的所在目录或者jar包路径、签名者以及证书等。
- ProtectionDomain
从类名就可以看出来这是保护域对象,它内部包含了CodeSource、PermissionCollection。
想了解更多相关内容可以查阅java之jvm学习笔记十(策略和保护域) 进行了解。
下面主要从debug的视角跟踪AccessController、AccessControlContext、SecurityPermission进行对比和理解。
在SecurityManagerTest.main()方法中改为C.print(false),采用AccessController.doPrivileged(PrivilegedAction)的方式进行调用。
print() 方法:
在执行SecurityPermission.implies(Permission)方法之前,会先在BasicPermissionCollection.implies(Permission)方法中找到匹配的Permission。
BasicPermissionCollection.implies(Permission)代码逻辑:
找到之后再调用Permission.implies(Permission)。
SecurityPermission类的逻辑都在其父类BasicPermission中,BasicPermission在构造方法中会init()进行简单的解析:
- 先判断后缀是否为*
- 如果是则对path进行处理,例如name = “x.x.*”
wildcard = true
path = “x.x.”
BasicPermission.init(String)
BasicPermission.implies(Permission)方法也是一个简单的对比逻辑:
SecurityPermission的使用案例
在SecurityPermission的构造参数中仅有name参数会参与到对比计算中,但是name支持’*'这个通配符;在使用时可以在.policy文件中配置:
在check时,可以将name以’.'进行任意的组合用于检测: