标题：Globus Toolkit
简介
  Globus Toolkit具有较为统一的国际标准，有利于整合现有资源，也易于维护和升级换代。现在，一些重要的公司，包括I BM和微软等都公开宣布支持Globus Toolkit。目前大多数网格项目都是采用基于GlobusToolkit所提供的协议及服务建设的。Globus对资源管理，安全、信息服务及数据管理等网格计算的关键理论进行研究并提供了基本的机制和接口。该项目早已开发出了能在各种平台上运行的网格计算工具软件(Toolkit)，支持网格计算和网格应用的一套服务和软件库。帮助规划和组建大型的网格试验平台，开发适合大型网格系统运行的大型应用程序。目前，Globus工具包机制已经被应用于全球数百个站点和几十个主要的网格计算项目：NASA网格(NASA IPG)、欧洲数据网格(Data Grid)和美国国家技术网格(NTG)等。
GlobusToolkit编写安全网格服务
来源：IBM DW 作者：Lavanya Ramakrishnan 
在网格这样的协同计算环境中，安全性是非常重要的问题。我们必须在应用程序的开发过程中正确实现安全机制，并且在部署阶段进行精确地配置，这一点十分关键。本文作者介绍了 Globus Toolkit 3.0 中的安全术语与机制。还提供了示例代码，展示了如何用 Globus Toolkit 3.0 在网格服务中实现消息级的安全性。简介Globus Toolkit 3.0 (GT3) 是开放网格服务基础设施（Open Grid Service Infrastructure, OGSI）的参考实现。其中提供了基于开放网格服务架构（Open Grid Service Architecture, OGSA）和 Web 服务架构构建网格服务的基础平台。这些服务可以实现资源共享、任务日程安排与组织，还可以访问网格上的各种分布式资源。对于网格环境中的应用程序来说，安全性是极其重要的。我们需要根据组织机构以及其他一些不同的策略，来控制对资源和数据的访问。因此，网格服务和客户端需要相互进行认证，而且必须访问经过授权的服务。OGSA 安全架构仍然处在开发阶段；所以，GT3 中的某些与安全性有关的 API 将来可能会发生变化。本文的内容基于最新的稳定版本 Globus Toolkit 3.0 。文中相当详细地介绍了网格服务与客户端的编写，并着重强调了安全机制。所以，本文假定您了解网格服务的基本术语，如通知（notification）、服务数据（service data），等等。我们鼓励您用 GT3 编写一个简单的网格服务。GT3 中的程序员教程是很好的起点。Globus Toolkit 的安全机制GT3 的安全机制与以前的版本一样，也是基于公钥基础设施（Public Key Infrastructure, PKI）。PKI 系统是一种信任层次系统，参与其中的实体通过其持有的证书，以及事前建立的软件与过程，实现身份的标识和确认。公钥的认证一般遵从 X.509 标准。对于基于 Globu 的安全网格服务和客户端而言，这意味着所有参与的实体（包括服务和客户端）都要具备一个符合 X.509 格式的身份标识。您可能已经有了由公司使用的 X.509 认证标识，或是 Globus Toolkit 以前版本中使用的 Globus 认证标识。有很多的商用产品都可以用来为网格建立认证中心（Certification Authority, CA）。然而，最简单的方法就是使用 Globus 小组发布的 Simple CA 包了，它可以生成 CA，从而可以在 Globus 网格中发出证书。授权，或称访问控制，这项功能用于控制哪些用户可以访问系统中的哪些部分。GT3 的授权基于简单的访问控制列表，这个列表位于明文文件 gridmap 中。在任务提交的过程中，Globus Toolkit 2.0 用这个 gridmap 文件将用户映射为远程资源上的用户 ID。GT3 对这一思路进行了扩展，实现了对 factory 和服务的访问控制策略。gridmap 文件与服务和 factory 相关联，用于限制谁可以访问所提供的功能。 
GT3 同时提供传输层和消息层的安全性。传输层的安全性依赖于对传输机制自身的保护。这种保护使得网格服务具有天生的安全性，但是却对传输形成依赖。消息级的安全性依赖于分别保护每一条消息。这样的机制很灵活，可以在任意的传输层之上发送消息。网格安全基础设施（Grid Security Infrastructure, GSI）基于公钥基础设施构建。在 Globus Toolkit 中，安全服务的基础是安全套接字层（Secure Socket Layer, SSL）。在 GT3 中，传输层安全性基于支持 GSI的HTTP 协议。消息层的安全性基于一些正在形成中的技术和标准，比如说 WS-Security、XML Encryption 以及 XML Signature 等。Globus Toolkit 正在朝消息级安全性的方向努力，而基于 GSI 的传输层安全性在将来的发布中可能会逐步淘汰，因此推荐应用程序使用消息级的安全机制。本文的其余部分将着重讨论消息级的安全机制。 
Gridmap 文件的格式 gridmap 文件为每个可以访问网格服务的人包含了一个条目。每一行的格式如下：“可区分名称”用户 ID 
gridmap 文件示例如下： 
/O=Grid/O=Globus/OU=cnidr,org/CN=Lavanya Ramakrishnan"
lavanya "/O=Grid/O=Globus/OU=cnidr,org/CN=John Doe" john开发安全的网格服务与客户端本节中，我们将依次介绍用 GT3 编写安全网格服务所需的各个步骤。GT3 提供的机制可以对服务进行配置，使其使用认证和服务级授权。GT3 中带的 API 可以帮助程序员将其他的安全机制集成进来，或者进行更细粒度的访问控制。首先，我们将描述如何设置适合于安全架构的环境。然后，我们会看到如何通过认证和授权来限制对服务的访问。最后解释一下如何对这些配置进行扩展，以便为 factory 提供访问控制机制。下面带编号的四个小节中包含一些代码清单，您可以根据您自己的需要使用这些代码，或是进行修改。 
1. 环境设置
GT3 提供的工具有助于您设置开发和部署网格服务的安全环境。请确认一下您是否已经用 $GLOBUS_LOCATION/bin/grid-cert-request 获取了相关证书。通常用户的私钥和公钥放置在主目录的 .globus 目录下。除此之外，您还需要创建 ~/.globus/cog.properties 文件。这个文件的内容应该是清单 1 中的格式。 
清单 1. cog.properties 文件格式 
usercert=/home//.globus/usercert.pem
userkey=/home//.globus/userkey.pem
proxy=/tmp/x509up_u[digit number]
cacert=/etc/grid-security/certificates/42864e48.0
usercert 和 userkey 两个变量指向公钥和私钥文件。在 GT3 中，您可以从长期的证据中派生出一个生命期更短的证据，供用户会话使用。这个较短期的文件称为 proxy（代理），生成的方法是使用 $GLOBUS_LOCATION/bin/grid-proxy-init，并在请求证书时使用密码短语（pass-phrase）。proxy变量指向这个代理文件。cacert 变量用于指向您所信任的 CA 证书。这些变量通常由 Globus 安装过程的 setup-gsi 脚本设置。 在启动任何一次网格会话之前，都不要忘记用 $GLOBUS_LOCATION/bin/grid-proxy-init 生成用户的代理。GT3 底层的安全库会找到这个用户代理，将其作为与这个用户运行的服务或者客户端相关联的代理（通过配置可使情况发生变化，稍后在清单 3 中将会讨论到）。GT3 的消息级安全是通过 Axis/JAX-RPC 处理程序实现的。server-config.wsdd 和 client-config.wsdd 必须定义适当的请求与响应流。默认情况下，GT3 会安装它们。 
Sun JVM 问题 有些人已经知道，Sun JVM 1.4.0/1.4.1 的 xalan.jar 文件中存在一些问题。这个文件不能与 GT3 中使用的 xml-security 包协同工作。请参阅 XML Security Library 的 安装指南 ，找到解决这个问题的方法。如果您使用的是 J2SE 1.3.1 ，需要下载并安装 JAAS 库。 
2. 编写安全的服务 本节中我们考虑一个简单的 HelloWorld 服务。HelloWorld 服务只有一个 sayHello() 方法，并可以订阅消息变化的通知。我们将告诉大家，如果想让这个 HelloWorld 变安全，应该进行哪些必需的修改。为了在服务实例上启用认证和授权，我们需要在部署描述符中设置若干属性，如清单 2 所示： 
清单 2. 保护服务实例用到的部署描述符 
<parameter name="instance-securityConfig" 
value="org/globus/ogsa/impl/security/descriptor/gsi-security-config.xml"/>
<parameter name="instance-authorization" value="gridmap"/>
<parameter name="instance-gridmap" value="/home/lavanya/gridmap"/>
instance-securityConfig 为安全属性指定部署描述符。这个参数用于在服务的安全属性之上提供粒度更细的控制。必须正确设置 instance-securityConfig 参数，认证才能生效。这里，我们将使用 GT3 提供的通用 gsi-security-config.xml 来实现 GSI 安全会话认证机制。您可以用可用的元素自己编写一个简单的安全描述符。安全部署描述符是从 classpath 处加载的；因此，您可以在实现该服务的 jar 文件中加入特定于应用程序的安全描述符。instance-authorization 参数定义了使用何种授权机制。可用的选项是 none、selfcode 和 gridmap 如果您在执行认证的时候没有初始化 instance-authorization，那么默认情况下执行 self 授权。 
如果这些安全性参数是在 一节中定义的，那么就适用于容器中的所有服务。默认情况下，用户环境中底层的库会取出服务证据和已信任证书。但是您可以在部署描述符中为每一个服务单独配置一组证据和与之关联的已信任证书，如清单 3 所示。与此类似，您也可以用 containerProxy 参数或 containerCert 和 containerKey 两个参数来设置与容器关联的证据。 
清单 3. 部署描述符中的其他选项 
// To set the service credential 
<parameter name="serviceProxy" value="[proxy file]"/> 
OR 
<parameter name="serviceCert" value="[certificate file]"/>
<parameter name="serviceKey" value=""/>
// To set the service trusted certificates 
<parameter name="trustedCertificates" value="[CA certificate locations]"/>
您可以按照一般网格服务的方式，根据 GWSDL 和 WSDL 生成服务的存根。在清单 4 中，我们展示了如何从服务的上下文中获取调用者的身份标识。清单中还阐明了其他一些可能的配置，服务端可能要求用这些配置设置安全通知回调。 
清单 4. HelloWorldImpl.java 服务的实现 
public class HelloWorldImpl extends GridServiceImpl implements 
HelloWorldPortType, CredentialRefreshListener {
public helloWorldImpl() {
super("HelloWorld");
}
public String sayHello(String in0) throws java.rmi.RemoteException {
String identity = SecurityManager.getManager().getCaller();
System.out.println("The identity is "+identity);
Subject subject = JaasSubject.getCurrentSubject();
System.out.println("Jaas Subject is "+ subject); 
...
...
// Set the properties on the service data for calling 
// the callback interface 
_state.setProperty(Constants.GSI_SEC_CONV, Constants.ENCRYPTION);
_state.setProperty(Constants.AUTHORIZATION,
NoAuthorization.getInstance());
// notify anyone subscribe to the ServiceData
_state.notifyChange();
return "hello" + in0 ;
}
public void postCreate(GridContext context) throws GridServiceException {
...
...
// The following lines illustrate how the properties specified in 
// the deployment descriptor could have been setup during service 
// instance creation incase the values were not known
// during deployment.
//String mapPath = "/home/lavanya/gridmap";
//context.getMessageContext().setProperty
("instance-authorization", new String("gridmap"));
//context.getMessageContext().setProperty
("instance-gridmap", mapPath);
}
public void refreshCredentials(org.ietf.jgss.GSSCredential creds){
}
private ServiceData _state; // wrapper for our custom data type
}
清单 4 中展示了在服务端设置的配置项。这项实现服务在通知订阅应用程序时扮演了客户端的角色。因此您需要在 ServiceData 中设置 Constants.GSI_SEC_CONV 和 Constants.AUTHORIZATION 两个属性。这些属性在下一节将详细讲述。我们还展示了在 sayHello() 方法调用的过程中，您应该如何使用 SecurityManager 获得调用者的身份标识。然后，您可以从上下文中获得 JAAS 调用的 subject。在服务实现的 postCreate() 中您也可以使用 GridContext 设置我们前面设在部署描述符中的参数。这项技术可以让我们在运行的时候设置服务实例参数，而不是在部署的时候绑定。证据和参与实体之间的信任关系是动态的，通常会在服务生命期中间发生改变。HelloWorld 服务实现了 CredentialRefreshListener 接口，这样就能自动刷新与服务关联的证据。在服务生命期中间对 gridmap 文件所做的任何改变都会反映出来。 
3. 编写安全的客户端
安全的网格客户端需要设置适当的属性，这样服务才能知道会话中需要使用的安全配置项。在这里，我们介绍如何设置其中的一些属性，以便能在服务中具备 GSI Secure Conversation。HelloWorldClient 是一个简单的客户端，它在 HelloWorldPortType 中调用 sayHello() 方法，查询服务数据，并订阅有关服务数据的通知。如清单 5 所示。 
清单 5. HelloWorldClient 
public class HelloWorldClient extends ServicePropertiesImpl implements 
NotificationSinkCallback {
public static void main (String[] args) {
helloWorldClient c = new helloWorldClient();
c.doHello();
}
public HelloWorldClient() {
}
public void doHello() {
try {
// Initialize the notification Manager 
NotificationSinkManager manager 
= NotificationSinkManager.getInstance("Secure");
manager.startListening(NotificationSinkManager.MAIN_THREAD);
// Setup the security properties to be used 
// by the NotificationManager 
HashMap props = new HashMap();
props.put(Constants.GSI_SEC_CONV, Constants.ENCRYPTION);
props.put(Constants.AUTHORIZATION, 
NoAuthorization.getInstance());
manager.init(props);
this.setProperty(Constants.GSI_SEC_CONV, Constants.ENCRYPTION);
this.setProperty(Constants.AUTHORIZATION, 
NoAuthorization.getInstance());
// For notification the client acts as a server point 
// and hence should specify who all the client
// trusts to receive notifications from. 
this.setProperty(Authorization.AUTHORIZATION, "gridmap");
GridMap map = new GridMap();
map.load("/home/lavanya/notification-gridmap");
SecureServicePropertiesHelper.setGridMap(this, map);
//Query service data 
OGSIServiceGridLocator locator = new OGSIServiceGridLocator();
String handle 
= "http://localhost:9080/ogsa/services/samples/HelloWorld;
GridService gridService 
= locator.getGridServicePort(new URL(handle));
//Set the properties on the stub to access the service data 
((Stub)gridService)._setProperty
(Constants.GSI_SEC_CONV, Constants.ENCRYPTION);
((Stub)gridService)._setProperty
(Constants.AUTHORIZATION, NoAuthorization.getInstance());
// Get Service Data Element "Our State"
ExtensibilityType extensibility =
gridService.findServiceData
(QueryHelper.getNamesQuery("MyState"));
ServiceDataValuesType serviceData =
AnyHelper.getAsServiceDataValues(extensibility);
MyStateType oData =
(MyStateType) AnyHelper.getAsSingleObject
(serviceData, MyStateType.class);
// Write service data
System.out.println("Queried message:" +oData.getLastMessage()); 
// Method call on the service 
String sink = manager.addListener
("MyState",null,new HandleType(handle,this);
HelloWorldNotificationServiceGridLocator hwLocator = 
new HelloWorldNotificationServiceGridLocator();
HelloWorldNotificationPortType hwPort = 
hwLocator.getHelloWorldNotificationPort(new URL(handle));
// Set the security properties on the Stub to access the service
((Stub)hwPort)._setProperty(Constants.GSI_SEC_CONV,
Constants.ENCRYPTION);
((Stub)hwPort)._setProperty(Constants.AUTHORIZATION, 
NoAuthorization.getInstance());
// Set this property if you want to delegate the 
// credential to the service 
((Stub)hwPort)._setProperty(GSIConstants.GSI_MODE, 
GSIConstants.GSI_MODE_LIMITED_DELEG);
System.out.println(hwPort.sayHello("Lavanya"));
} catch (Exception e) {
e.printStackTrace();
}
}
/*
Called whenever serviceData is modified on the service side
*/
public void deliverNotification(ExtensibilityType any)
throws RemoteException {
... 
}
}
对于启用 GSI Secure Conversation 的客户端来说，必须设置 Constants.GSI_SEC_CONV 属性，以用于指示使用的是下面两种消息级保护机制中的哪一种：
·签名 (Constants.SIGNATURE)
·加密 (Constants.ENCRYPTION) 
清单 5 中的另一个属性是为 NoAuthorization.getInstance() 方法设置的 Constants.AUTHORIZATION 它的作用是关闭客户端授权。还需要在通知管理器中设置安全参数。方法是用想要的属性初始化一个 HashMap，然后将其与管理器相关联。此外，当客户端接收通知的时候，它扮演的是服务器的角色。因此您需要将访问控制与回调接口相关联。将 Authorization.AUTHORIZATION 属性设置到 gridmap 中，然后使用 SecureServicePropertiesHelper 关联相应的 gridmap 文件。与此类似，当您想查询服务数据，或者是调用了 portType 接口上的方法时，可以看到如何在 Stub 接口上设置相应的属性。当服务的行为方式需要它用客户端的证据来访问另外的服务时，您可以委托一个证据。为了启用证据委托，可以将 GSIConstants.GSI_MODE 设置为GSIConstants.GSI_MODE_LIMITED_DELEG。 
还可能需要使用其他的属性来配置 GSI Secure Conversation 与 GSI XML Signature 的设置（例如， GSIConstants.GSI_CREDENTIALS、Constants.GSI_XML_SIGNATURE）。可以采用上述类似的方式来设置这些属性。 
4. 安全的 factory
OGSA 中的 factory 接口允许用户创建多个网格服务实例。您可以完全根据自己的需要，将对服务实例的访问限制到某组特定的用户，您还应该限制谁可以创建这些服务。实现的方法是为 factory 实例创建一个访问控制，这样就可以限制哪些人可以访问 factory 和创建服务实例了。在 GT3 中，可以在部署描述符中设置适当的参数，如清单 6 所示。 
清单 6. 安全 factory 的部署描述符 
<parameter name="securityConfig" 
value="org/globus/ogsa/impl/security/descriptor/gsi-security-config.xml"/> 
<parameter name="authorization" value="gridmap"/>
<parameter name="gridmap" value="/home/lavanya/gridmap"/>
清单 6 显示，设置参数的方法与为服务实例设置参数的方法相似。securityConfig 指定安全属性的部署描述符。这有助于在服务的安全属性之上提供粒度更细的控制。GT3 附带的通用 gsi-security-config.xml 可以提供 GSI 安全对话认证机制。authorization 参数指定使用何种授权机制。可选项为 none、selfcode 或 gridmap。如如果您使用了 gridmap 授权，请将 gridmap 参数指向 gridmap 文件。当您在像清单 6 那样保护 factory 的时候，调用之前应该在 factory 存根中设置 Constants.GSI_SEC_CONV 和 Constants.AUTHORIZATION，以便创建服务实例。清单 7 展示了具体的方法。 
清单 7. 创建安全服务 
...
OGSIServiceGridLocator factoryService = new OGSIServiceGridLocator();
Factory factory = factoryService.getFactoryPort(new HandleType(handle));
...
// securing the factory stub 
((Stub) factory)._setProperty(Constants.GSI_SEC_CONV, 
Constants.ENCRYPTION); 
((Stub) factory)._setProperty(Constants.AUTHORIZATION, 
NoAuthorization.getInstance()); 
GridServiceFactory gridFactory = new GridServiceFactory(factory);
LocatorType locator = gridFactory.createService(null, id);
...结束语编写网格服务的主要挑战之一就是提供适当的安全机制，并使其有效工作。本文讨论了 GT3 提供的一些安全机制。本文还向您展示了如何用这些机制编写安全的网格服务和客户端。 
关于作者 Lavanya Ramakrishnan 为 MCNC 研究开发协会（MCNC Research and Development Institute，MCNC-RDI）工作。这是一个非赢利性的研究组织，位于美国北卡罗来纳州。MCNC-RDI 还为 MCNC 网格计算与网络服务（MCNC Grid Computing and Networking Services）的很多网格研究活动与项目提供支持，后者正在发起美国第一个州际网格。Ramakrishnan 目前正为使用 Globus Toolkit 3.0 的网格信息获取系统构建安全基础设施，还在向网格功能中加入基于门户（portal）的接口。除此之外，她参与测试和评估了很多网格中间件，以便在若干网格试验台上部署，其中包括 NASA 资助的虚拟协作中心（Virtual Collaborative Center）。Remakrishnan女士还参加了全球网格论坛（Global Grid Forum，GGF）的安全问题小组。[1]