OSGi代码权限与Java Security机制

来源:互联网 发布:网络招商 编辑:程序博客网 时间:2024/05/01 07:32


在OSGi开发中,我们常用的getBundleContext().getServiceReferences(String, String)调用,偶尔会出现访问失败,返回null的问题。这是因为OSGi在若干关键的方法中,基于java.security.*类,实现了代码层次的访问权限控制。

在org.eclipse.osgi.framework.internal.core.Framework.getServiceReferences(String, String, BundleContextImpl, boolean)方法中,我们看到有个checkGetServicePermission(String serviceName)方法,其实现如下:

protected void checkGetServicePermission(String serviceName){     SecurityManager localSecurityManager = System.getSecurityManager();     if (localSecurityManager != null)          localSecurityManager.checkPermission(new ServicePermission(serviceName, "get"));}


其中比较重要的类有:

java.security.AccessController

java.lang.SecurityManager


所有的权限判断,最终会在java.security.AccessController.checkPermission(Permission)方法中处理,在此方法中:

1. 调用native方法,获取 java.security.ProtectionDomain[] array。此方法由jvm自己native方法实现,主要实现了从当前调用堆栈上的jars中,解析ProtectionDomain类型。

2. 迭代调用java.security.ProtectionDomain.implies(Permission)方法,一旦某给ProtectionDomain判断失败,则会抛出AccessControlException,此次访问被拒绝。


在IBM Domino8的OSGi的架构中,从传统的domino nsf中调用OSGi插件中的代码,极有可能访问被拒绝。因为此时的ProtectionDomain[]  Array类似:

1.

ProtectionDomain
CodeSource=CodeSource, url=file:/C:/Program Files (x86)/IBM/Lotus/Domino/osgi/rcp/eclipse/plugins/org.eclipse.osgi_3.4.3.R34x_v20081215-1030-RCP20100710-0200.jar

2.

EquinoxProtectionDomain
CodeSource=CodeSource, url=file:/C:/Program Files (x86)/IBM/Lotus/Domino/data/domino/workspace/applications/eclipse/plugins/com.smartdot.indigo.common_1.0.0.201202171556.jar, <no certificates>

3.

EquinoxProtectionDomain
CodeSource=CodeSource, url=file:/C:/Program Files (x86)/IBM/Lotus/Domino/data/domino/workspace/applications/eclipse/plugins/com.smartdot.misc.xsp.log_1.0.0.201202171556.jar, <no certificates>

4.

EquinoxProtectionDomain
CodeSource=CodeSource, url=file:/C:/Program Files (x86)/IBM/Lotus/Domino/osgi/shared/eclipse/plugins/com.ibm.jscript_8.5.2.20100730-1730/lib/lwpd.commons.ibmjs.jar, <no certificates>

5.

EquinoxProtectionDomain
CodeSource=CodeSource, url=file:/C:/Program Files (x86)/IBM/Lotus/Domino/data/domino/workspace/applications/eclipse/plugins/com.smartdot.misc.xsp.js_1.0.0.201202171556.jar, <no certificates>

6. 

ProtectionDomain
CodeSource=CodeSource, url=xspnsf://server:0/demo1.nsf/script/, <no certificates>
ClassLoader=<null>
<no principals>
Permissions:
        static: java.security.Permissions@8f108f1 (
 (java.net.SocketPermission localhost:1024- listen,resolve)
 (java.util.PropertyPermission line.separator read)
 (java.util.PropertyPermission java.vendor.url read)
 (java.util.PropertyPermission java.vm.vendor read)
 (java.util.PropertyPermission javax.realtime.version read)
 (java.util.PropertyPermission file.separator read)
 (java.util.PropertyPermission java.vm.version read)
 (java.util.PropertyPermission java.vm.specification.name read)
 (java.util.PropertyPermission java.vm.name read)
 (java.util.PropertyPermission path.separator read)
 (java.util.PropertyPermission os.version read)
 (java.util.PropertyPermission java.version read)
 (java.util.PropertyPermission os.name read)
 (java.util.PropertyPermission java.vm.specification.version read)
 (java.util.PropertyPermission os.arch read)
 (java.util.PropertyPermission java.vm.specification.vendor read)
 (java.util.PropertyPermission java.specification.vendor read)
 (java.util.PropertyPermission java.vendor read)
 (java.util.PropertyPermission java.specification.name read)
 (java.util.PropertyPermission java.class.version read)
 (java.util.PropertyPermission java.specification.version read)
 (java.lang.RuntimePermission getClassLoader)
 (java.lang.RuntimePermission stopThread)
 (java.lang.RuntimePermission setContextClassLoader)
 (java.lang.RuntimePermission createClassLoader)
)

我们看到, 在demo1.nsf中,内置定义了若干访问权限。那么如何屏蔽此问题,使得从OSGi外部能正确的访问到内部受控的代码?我们发现,EquinoxProtectionDomain是在OSGi bundle DefaultClassLoader中加载bundle jar的时候就生成的,在new的时候,被jvm记录下来,并且和当前的ClassLoader绑定,以后再判断权限出,根据调用堆栈上的类,收集到相应ClassLoader new出来的ProtectionDomain,然后用这些收集来的ProtectionDomain进行判断。似乎我们找不到切入点去动态修改某个ProtectionDomain的权限了。但是,如果System.setSecurityManager(SecurityManager instance); 有权限被调用呢,我们就可以绕开当前线程以后的所有权限判断,只需要做一个自己的SecurityManager,在其checkPermission() 方法中什么也不做。


另一种侵入式修改${jvm}/lib/security/java.policy 文本文件,加入下面的内容,开放全部权限。

grant {
    permission java.security.AllPermission
};


当然可以在对permission按照jars所在目录授权。

grant codeBase "file:${notes.binary}/data/domino/workspace/applications/-" {
    permission java.security.AllPermission
};

grant {
    permission java.lang.RuntimePermission "createClassLoader";
    permission java.lang.RuntimePermission "getClassLoader";
    permission java.lang.RuntimePermission "setContextClassLoader";
};


通常情况下,我们代码中如果要对某个代码片段加权限判断,可以如下操作。此权限可以在jvm的security配置文件中配置。至于在jar中怎么配置,猜测应该在MANIFEST.MF文件中,具体方法还需google.

String permissionName= "getService"; // Your service name define.
SecurityManager securityManager = System.getSecurityManager(); // Can be customized.AccessController.doPrivileged(new PrivilegedAction(securityManager, permissionName) {      public Object run()      {         // your operation here...     }};

关于Java Security机制,请参考:

http://hi.baidu.com/gelyea/blog/item/1cc8fa13ea674c22dd5401ca.html




	
				
		
原创粉丝点击