3 安全
在一个典型的基于Jini技术的应用中,一个客户端从某处(例如,从一个lookup service或者一个与其他服务通讯的结果中)得到服务代理,然后调用那个代理的方法与服务进行通讯。许多应用需要对远程的通讯进行加密。那就需要以下的一个或几个技术:
* Mutual authentication(client and server)
* Authorization(access checksums)
* Integrity(cryptograhic checksums)
* Confidentiallity(encryption)
这些实典型加密数据通讯的需求;但是Jini安全模型有一个附加的需要:代码完整性检查(code integrity)。在Jini和Java RMI模型中一个对象的数据是在一个远程调用中得到的,但是他的代码是作为那个远程调用的的结果在带外(out-of-band)下载得到的。一个应用需要通过两方面确认它所收到的对象的信任信息:对象代码的完整性,以及它的数据的完整性。
**********************************************************************************************************
带外(out-of-band)的概念不是很理解参考以下网管中in-band和out-of-ban的区别吧:
in-band & out-of-band
从技术的角度,网络管理可分为带外管理(out-of-band )和带内管理(in-band )两种管理模式。所谓带内管理,是指网络的管理控制信息与用户网络的承载业务信息通过同一个逻辑信道传送;而在带外管理模式中,网络的管理控制信息与用户网络的承载业务信息在不同的逻辑信道传送。一般说来,由于传送信息的隔离,带外管理比带内管理安全程度更高。
带外数据(OOB:Out-Of-Band)
转自:iSeries信息中心
带外(00B)数据是特定于用户的数据,仅对面向连接的(流)套接字有意义。流数据通常是按发送次序接收的。OOB 数据的接收与它在流中的位置无关(与发送它的次序无关)。这是有可能的,原因是数据是按以下方式标记的,在将数据从程序 A 发送至程序 B 时,会通知程序 B 数据到达。
OOB 数据仅在 AF_INET(SOCK_STREAM)和 AF_INET6(SOCK_STREAM)上受支持。
通过在 send()、sendto() 和 sendmsg() 函数上指定 MSG_OOB 标志来发送 OOB 数据。
传送 OOB 数据与传送常规数据一样。它是在所有缓冲数据之后发送的。换句话说,OOB 数据的优先级别没有可能缓冲的任何数据的优先级别高;数据是按其发送次序传送的。
在接收端,事情有一点复杂:
●套接字 API 通过使用 OOB 标记程序了解在系统上接收到的 OOB 数据。OOB 标记程序指向发送的 OOB 数据中的最后一个字节。(注意:指示 OOB 标记程序指向哪个字节的值是在系统基础上设置的。此值在 TCP 连接的本地和远程端必须一致。使用此值的套接字应用程序在使用它时必须在客户机和服务器应用程序之间保持一致。)
SIOCATMARK ioctl() 请求确定读指针是否正指向最后一个 OOB 字节。(注意:如果发送多次出现的 OOB 数据,则 OOB 标记程序指向最后一次 OOB 数据出现的最后一个 OOB 字节。)
●无论 OOB 数据是否以直接插入方式接收,输入操作会一直处理数据直至遇到 OOB 标记程序(如果发送了 OOB 数据的话)。
●recv()、recvmsg() 或 recvfrom() 函数(设置有 MSG_OOB 标志)用于接收 OOB 数据。如果其中一个接收函数完成并发生下列情况之一,会返回错误 [EINVAL]。
1、未设置套接字选项 SO_OOBINLINE,也没有 OOB 数据可接收。
2、设置了套接字选项 SO_OOBINLINE。
如果未设置套接字选项 SO_OOBINLINE,且发送程序发送的 OOB 数据的大小超过 1 字节,则除最后一个字节之外的所有字节都被视作普通数据。(普通数据表示接收程序可接收数据而不指定 MSG_OOB 标志。)发送的 OOB 数据的最后一个字节未存储在普通数据流中。只能发出 recv()、recvmsg() 或 recvfrom() 函数(设置有 MSG_OOB 标志)来检索此字节。如果未设置 MSG_OOB 标志而发出接收,将检索普通数据,OOB 字节将被删除。而且,如果发送多次出现的 OOB 数据,则先前出现的 OOB 数据将会丢失,仅记住最后一次 OOB 数据出现的 OOB 数据位置。
如果设置了套接字选项 SO_OOBINLINE,则发送的所有 OOB 数据都存储在普通数据流中。可通过发出下列三个接收函数之一而不指定 MSG_OOB 标志(如果指定它的话,将返回错误 [EINVAL])来检索数据。如果发送多次出现的 OOB 数据,OOB 数据不会丢失。
●如果未设置 SO_OOBINLINE 且已接收到 OOB 数据,则不会废弃 OOB 数据,用户会将 SO_OOBINLINE 设置为开。初始 OOB 字节被视作普通数据。
●如果未设置 SO_OOBINLINE 且已发送 OOB 数据,同时接收程序发出了输入函数以接收 OOB 数据,则 OOB 标记程序仍然有效。接收程序仍然可以检查读指针是否在 OOB 标记程序上,即使接收到 OOB 字节。
************************************************************************************************************
这个发行版本提供了一个框架用来做信任验证信息,以及一个基于约束的(constraint-based)远程调用模型来使得使得应用可以对远程调用指定不同的需求(比如安全需求)。底层框架同时也提供了代码完整性检查(code integrity)的基础部分。
3.1 约束和远程调用
上面描述的安全需求可以被表示成远程调用的约束。一个约束就是一个客户端指定的应用于代理与它的服务之间的远程通讯的行为特征需求。一个代理可以通过实现net.jini.core.constraint.RemoteMethodControl接口来使得客户端能够为代理的远程通讯指定约束。基于约束的远程调用模型是概要(general)的,提供与安全相关的约束类型以及其他的约束类型。
一个使用约束的例子就是客户端需要在于一个服务通过代理通讯之前鉴别一个服务(比如一个银行)的标识。在这个例子中,服务的代理可以通过实现RemoteMethodControl接口来使得客户端对任何一个通过该代理执行的远程调用设置服务器鉴别的约束。满足这些约束是代理的职责,但是是否能够相信代理带来的信任信息确实客户端的职责。
每个约束都被表现为一个net.jini.core.constrait.InvocationConstraint的接口。一个InvacationConstraint的实例表示"what"但不是"how";也就是说,一个约束代表着这个约束象征着"什么"("what"),而不是代表着这个约束应该如何被满足。一个代理有责任使用正确的传输和协议来满足客户端所设置的约束。因为约束是被抽象的表述的,安全实现是可插入的,因此是有能力支持各种不同的协议的,比如SSL,和Kerberos。请参看net.jini.core.constraint的包文档来查找更多的有关pre-defined基础约束。
在一个客户端给代理设置一个约束前,客户端首先要确认这个代理是一个可被信任用来执行约束的代理。因为代理也许是从一个不被信任的源头得到的。如果客户端不确认代理的信任度,那么代理可以忽略client设置的约束并且执行非加密的数据传输,从而泄露client或者server的身份信息,甚至更遭。当客户端确认了代理的信任信息后,它就可以对代理设置约束来制定任何的安全需要,比如服务器的证明。
一旦客户端信任了一个代理,他可能还需要授予代理附加的许可。因为通常没有取得信任的代码都被事先配置了最低的许可,通过附加许可可以使得该代理以后的调用被正确执行。一个代理也许会请求net.jini.security.AuthenticationPermision,从而它可以验证服务器。一个客户端一定不能在认证一个代理之前授予其许可。从而确保不会产生代理滥用授权带来的危害。
总结一下,当一个客户端从未信任的源头取得代理后,需要在执行代理的方法前按照以下的步骤"prepare"代理。以下各个步骤地全部的需要在net.jini.security包文档中有详细描述:
* 确认代理的信任信息
* 为代理授权
* 给代理设置约束
以上的步骤可以被打包在一个独立的操作中---proxy preparation,这个术语意味着“为代理的远程调用做准备”。客户端的接口net.jini.security.ProxyPreparer将这些代理准备工作打包进了一个独立的方法,prepareProxy。
net.jini.security.BasicProxyPreparer类,一个ProxyPreparer接口的标准实现,在准备一个代理的远程调用前执行三个必须的步骤。大多数的开发人员可以使用BasicProxyPreparer实例来进行代理的准备工作,而不必关系信任信息确认背后的所有细节(下面解释一些细节)。如果其他的应用需要对信任信息确认,设置约束,以及授权的行为作定制的话可以继承BasicProxyPreparer。
3.2 使用BasicProxyPreparer进行代理准备
BasicProxyPreparer类封装了信任信息确认,设置约束,为代理授权这三个步骤。一个BasicaProxyPreparer实例可以用不同的方式进行构造,支持一下列出的很多通用的代理准备用例:
* 信任信息确认,为代理授权,设置新的约束:给一个从没有取得信任的源头得到的代理做准备。
* 设置新的约束:给一个从已经取得信任的源头(但是该源头还没有被确认支持指定的约束)得到的具有完整性保护的已经信任的代理做准备。
* 授权:给一个从已经取得信任的源头(并且该源头已经被确认支持指定的约束)得到的具有完整性保护的已经信任的代理做准备。
* 什么也不做:当查询一个可选的配置实体时被用来当作默认的动作。或者被用来准备一个不具有安全性的代理。
net.jini.security的静态的方法Security.verifyObjectTrust和Security.grant分别实现了信任信息确认和授权。约束可以通过调用实现了RemoteMethodControl接口的代理中的setConstraints方法进行设定。一个BasicProxyPreparer使用这三个机制来实现指定的代理准备。
下面的三个段落描述了BasicProxyPreparer实例使用这三个步骤进行代理准备的机制。处于讨论的目的,让我们假设这个BasicProxyPrepare实例是按照如下方式进行构造的:
new BasicProxyPreparer(true,constraints,permissions)
参数true,指出代理应该被验证信任信息,constraints是一个MethodConstraints对象(这是一个设给代理的包含了per-method约束的对象)。permissions参数是一个java.security.Permissions的数组,这些Permissions将被用来给代理授权。
以下的UML时序图说明了带了准备,和信任信息确认的处理过程。
Proxy Preparation:说明信任信息确认,授权,以及为代理设置新的约束。
Non-Smart代理信任信息确认:说明如何使用一个ProxyTrustVerifier来确认non-smart代理(例如一个简单的Jini ERI代理)的信任信息。
Smart代理的信任信息确认:说明如何使用ProxyTrustVerifier来确认一个smart代理的信任信息。
原文出处:http://cs.ttu.edu/~sorcer/resources/jini-docs/arch2_0.html
第一次自己翻译文章,希望还能看:)
Jini(TM) Technology Starter Kit Overview V2.1
这篇文档对Jini(TM) Technology Starter Kit V2.1中的新组件进行了概览,并阐述了这些组件是如何组合起来与目前现存的jini技术的底层架构进行整合的。这篇文档中的的很多信息都可以在包,接口以及类文档中找到,不过这篇文档给出了更高层的总览。在其中更帮读者指明了在哪里可以找到更多的信息。
1 Jini架构总览
Jini系统架构有三类组成:编程模型,底层框架,服务。原始的《Jini 架构说明》对这三个类别进行了以下定义:
* 底层框架(infrastructure)是一组用来建立一个联合的Jini系统的组件。
* 服务(services)则是这个联合系统中的实体。
* 编程模型(programming model)是一组用来构造可靠的服务的接口。
起初,编程模型定义了租约,事件通知,和事务。底层框架由发现/加入(discovery/join)协议和查找服务(Lookup service)组成。上一个版本的Starter Kit导入了以下Jini technology-enabled服务(Jini服务):
* Lookup Service(reggie)
* Transaction Manager Service(mahalo)
* Lease Renewal Service(norm)
* Event Mailbox Service(mercury)
* Lookup Discovery Service(fiddler)
* JavaSpaces(TM) Service(outrigger)
Starter Kit V2.0发行版对前两个类别(infrastructre,services)加入了一些组件,其中一些组件同时跨越了这两个类别。而且,这个发行版提供了对现有服务的升级来提供底层架构和编程模型。加入的组建按如下总结:
对编程模型的添加:
* Configuration
* Exporter
* ProxyPreparer
新的底层框架:
* Security
* Invocation Constraints
* Jini extensible remote invocation(Jini ERI)
* Dynamic Policy
* Preferred Class Loading
* Discovery Protocol V2
对服务的添加:
每一个服务都被升级到支持使用Configuration进行配置。大多数的服务以前都是通过系统属性进行配置。这些服务现在已经可以使用在Configuration中的实体进行配置 了。新的可配置的行为是:远程服务导出(Remote service exporting)和代理准备(proxy preparation)。
1.1 目标
在Jini架构中新添加的部分的主要目标是:
* 为基于jini技术的程序提供安全支持。(Security infrastructure)
* 提供可配置的应用。(Configuration)
* 统一客户端和服务器端的编程模型。(ProxyPreparer和Exporter)
* 提供一个支持可插入的调用层行为,以及可插入的传输实现。(Provide a java rmi implementation taht supports pluggable invocation layer behavior and pluggable transport providers)。
扩大jini架构的最主要动力来自于提供新的编程模型以及基于jini的应用程序对底层框架中的安全管理的需要。上一个发行版本中缺少在很多应用程序中需要的对安全的直接支持--即对服务远程调用的基础网络安全。这个目标已经在新的安全底层框架和基于约束的远程调用模型(constraint-based remote invocation model)中得以实现。
另外一个重要的目标就是更好的为服务的编程人员提供统一的编程模型。提供上一个版本中缺少的实现,倒入,部署服务所需的一致的API。加密的远程调用导致了客户端必须增加确认的步骤,所以这个发行版导入了一个统一的客户端API来处理远程调用前的“Preparation”步骤。另外,通过将部署时信息从应用中剥离,可以使应用程序的开发者轻松的完成部署任务。这个版本中的配置API被用来提供简单而统一的取得部署描述信息(deployment-specific)的方式。从而使得编程模型变成一个对可插入的安全,导出,传输和其他服务支持具有统一支持的框架。
最后一个目标就是,提供一个JAVA RMI编程模型的实现,该实现支持远程调用中的约束(安全模型中至关重要的部分),并且支持可插入的调用和派发行为,就如同在每个对象中基础的可插入的传输功能,这些特点是JAVA2 SDK中的RMI所不具备的功能。JINI ERI API提供了这样一个可插入的JAVA RMI编程模型的实现。
2 编程模型
在进行深入的安全架构研究之前,先理解一些增加的编程模型,配置,导出和代理预备是很重要的。他们被用来简化普通的应用开发特别是安全相关的应用开发。
2.1 配置
当一个应用程序使用一个抽象层将源代码与特殊的部署信息相互剥离,而不是仅仅的与其绑定时,这个应用将非常易于测试部署和改进。比如说服务提供者接口。这样的应用允许部署信息在部署时才被配置。明显的优势就是,应用程序的源代码不需要改变就可以按照部署需要增加组件。如果部署需要改变,只需要改变配置而应用程序无需任何改变。
net.jini.config.Configuration API通过提供一个简单的统一的方式来得到配置应用程序所需的的对象来完成这项工作。一个应用程序可以从Configuration中得到对象而不是明确的自己来组建一个实例,从而避免与部署信息绑定。典型的对象应该从一个Exporter或者ProxyPrepare的Configuration中得到(后面讨论)。
一个应用可以使用net.jini.config.ConfigurationProvider来得到Configuration的实现。在应用中使用ConfigurationProvider允许应用程序的部署器在部署时指定最合适的配置实现。一个给定的配置实现可以从文件,数据库或其他地方得到读取配置信息。
标准的默认的配置实现是net.jini.config.ConfigurationFile。它使用java语言实现从配置文件或者URLS中读取配置信息产生产生对象的功能。
2.2 导出器和服务器端实现模型
在基于jini技术的应用程序中,调用一个jini服务的方法有统一的client端模型:一个客户端只是简单的调用服务代理的一个方法来初始化与服务对象的远程通讯,这是一个尊从通用的JAVA RMI模型的调用语法。
而Jini应用的服务器端实现模型却并不是统一的。一个应用开发者通常实现一个服务,并将其直接与特定的实现以及特定的远程通讯模型相互绑定后导出。如果服务的服务的导出方式发生轻微的改变,则需要改动服务器端应用程序的代码。例如,一个应用的部署方式要求使用一个不同的端口号或Socket工厂导出一个服务,甚至服务需要以全新的方式进行远程通讯,比如说不同的RMI编程模型实现。
net.jini.Exporter接口通过为导出和卸载远程对象提供一个抽象层统一了服务器端的实现模型。具体的导出和卸载行为包括远程调用的通讯协议,和增加的调用语法在特殊的Exporter接口的实现中进行定义。
本次的发行版提供了很多标准的Exporter实现,同时也是Java RMI的编程模型。以下的列表列出了这些实现:
Exporter Equivalent Class
net.jini.jrmp.JrmpExporter java.rmi.server.UnicastRemoteObject
net.jini.iiop.IiopExporter javax.rmi.PortableRemoteObject
net.jini.jeri.BasicJeriExporter itself
应用程序可以将Exporter Interface与Configuration一起使用从而使用一种在部署时可配置的方法导出远程对象。下面的代码展示了可配置的导出:
import java.rmi.*;
import net.jini.config.*;
import net.jini.export.*;
public class Example implements Remote{
public static void main(String[] args) throws Exception{
Configuration config = ConfigurationProvider.getInstance(args);
Exporter exporter = (Exporter)config.getEntry(
"Example","exporter",Exporter.class);
Remote proxy = exporter.export(new Example());
System.out.pringln(proxy);
exporter.unexport(true);
}
}
这个应用可以将下面的配置文件作为命令行参数进行配置(配置文件使用ConfigurationFile语法)。配置文件描述Exporter为一个JrmpExporter,一个能够产生使用JRMP协议代理的Exporter。
import net.jini.jrmp.*;
Example{
exporter = new JrmpExporter();
}
或者,可以为部署指定一个BasicJeriExporter(一个使用Jini ERI导出远程对象的Exporter)Exporter,用来在任何的匿名TCP端口上导出对象。
import net.jini.jeri.*;
import net.jini.jeri.tcp.*;
Example{
Exporter = new BasicJeriExporter(TcpServerEndpoint.getInstance(0));
}
2.3 ProxyPreparer和Client-Side Invocation Model
新的安全模型需要应用在调用一个服务代理的方法前执行它的一些pre-invocation“准备”。这是因为一个应用也许会从没有取得信任的来源获取服务代理。因此,在应用使用代理之前,应用应该执行诸如确认代理中的信任信息等操作,一旦信任信息被确认后还要为代理分配权限。
这些安全需求给client-side调用模型增加了一个步骤。net.jini.security.ProxyPreparer接口将"proxy preparation"的操作提炼到了一个单独的方法中。prepareProxy,以此来统一客户端在跨越使用安全和非安全的代理的调用模型。
一个ProxyPreparer可以与Configuration一起使用来允许可配置的Proxy Preparation。以下的代码是从hello例子中提取出来的:
ProxyPreparer preparer = (ProxyPreparer)config.getEntry(
"com.sun.jini.example.hello.Client","preparer",ProxyPreparer.class,new BasicProxyPreparer());
server = (Hello)preparer.prepareProxy(Server);
System.out.println("Server says:" + server.sayHello());
对getEntry的调用为没有在配置文件中定义的实体提供了一个默认的(new BasicProxyPreparer())。一个net.jini.security.BasicProxyPreparer的实例可以使用指定的参数进行初始化。该参数说明是否有一个proxy将被被传给它的prepareProxy方法中,来确定信任信任信息,以及其他的安全相关的操作。一个没有使用参数初始化的BasicProxyPreparer指出了"do nothing" proxyPreparer,只是简单的将传入的proxy返回。
如果一个应用部署有安全需要,那么这个应用可以使用一个被正确的参数初始化的BasicProxyPreparer,或者其他的ProxyPreparer实现进行部署。