Web services 安全实践: 基于 HTTP Basic Authentication 为 Web services 配置传输层安全机制
转载:http://www.ibm.com/developerworks/cn/webservices/1106_webservicessecurity/
简介
正如"HTTP Basic Authentication"这个名字,它是 Authentication( 认证 ) 中最简单的方法。长期以来,这种认证方法被广泛的使用。当你通过 HTTP 协议去访问一个使用 Basic Authentication 保护的资源时,服务器通常会在 HTTP 请求的 Response 中加入一个"401 需要身份验证"的 Header,来通知客户提供用户凭证,以使用资源。如果你正在使用 Internet Explorer 或者 Mozilla Firefox 这样的可视化浏览器来访问需要认证的资源,浏览器会弹出一个窗口,让你输入用户名和密码,如果所输入的用户名在资源使用者的验证列表,并且密码完全正确,此时,用户才可以访问受限的资源。那么什么是 HTTP Basic Authentication 呢?如何在不同的服务器上配置 Basic Authentication 呢?下面本文将展开介绍。
HTTP Basic Authentication 介绍
HTTP BASIC 认证的基本流程如图 1 所示,
图 1. BASIC HTTP认证基本流程
HTTP Basic Authentication 是指客户端在使用 HTTP 协议访问受限资源时,必须使用用户名和密码在一个指定的域 (Realm) 中获取认证。在正式开始之前,我们需要明白以下名词的含义:
- Authentication,即认证,验证。它是一种确认的过程,通过这样的认证过程,你可以确定某物体是不是它所声称的那种物体。这通常会涉及到用户名和密码,也可能是身份证明,或生物特征,如视网膜等。
- Realm,即域。一个 Realm 就是一系列用户名和密码的“数据库”,它通常用来保存、识别某个或某些 Web 应用中有效的用户和密码。它还定义了每个有效用户所对应的角色。
本文将介绍如何使用 HTTP BASIC Authentication 来保护 Web services endpoint 服务资源,当 Web services 的 Endpoints 被设置为 BASIC HTTP 认证才能访问的受限资源时,用户必须提供用户名密码才能使用它们,基本的流程如图 2 所示。
图 2. Web services 客户端访问受限 Web services 服务流程
下面,本文将以 Tomcat 何 WebSphere Application Server 为例,分别讲述如何配置 Web services 的 endpoint 为受限资源,并使用 Web services 静态和动态客户端分别加以测试。
为 Tomcat 配置 Basic Authentication
本节将详细讲述如何在 Tomcat 下使用 Basic Authentication 来增强 Axis 实现的 Web services 访问的安全性。本文使用 Eclipse 来开发相关的例子,在这里假设您已经安装了相关的环境。
创建 Web services Provider 应用
在 Eclipse 中新建一个 Dynamic Web Project,并将其命名为“TomcatAxis”如图 3 所示:
图 3. 创建动态 WEB 工程
该工程的目录结构如图 4 所示:
图 4. 工程结构
为 Web services 添加实现
创建一个基于 Axis 实现的 Web Service,本文采取“Bottom up Java bean Web Service”方式创建,其具体操作过程为:
- 创建该 Web services 的实现类,代码如下
清单 1. Web services Provider 实现代码
package sample.test; public class ServiceImpl { /** * return the summation of the two integer arguments * @param addend * @param augend * @return */ public int sum(int addend, int augend) { return addend + augend; } }
- 基于该实现类,创建 Web Service,如图 5 所示
图 5. 创建 Web Service
完成上述步骤后,会在 /TomcatAxis/WebContent/wsdl/ 目录下创建一个名称为“ServiceImpl.wsdl”的 WSDL 文件。
- 将 Web Application 部署到 Tomcat 上,使用 Eclipse 自带的 Web services 测试工具“Web services Explorer”来测试所创建的 Web services 是否能被使用,如图 6 所示
图 6. 测试所创建的 Web services
在确认所创建的 Web services 能够正常使用后,需要为 Web Application 配置 Basic Authentication。
为 Web Application 配置 Basic Authentication:
- 打开 Tomcat 安装目录下的“conf”文件夹,修改文件“tomcat-users.xml”,该文件是用来存储 Tomcat 预加载的用户和角色定义的,此文件即是上文提到的 Realm。在“<tomcat-users>”中加入如下用户和角色:
清单 2. 定义用户及其角色
<!-- Web services invoker role --> <role rolename="WsInvokerRole"/> <!-- Web services invokers/users --> <user username="wsaxis" password="wsaxis" roles="WsInvokerRole"/>
- 打开 Web 应用“TomcatAxis”的部署描述符:web.xml 文件,并在“<web-app>”中加入如下片段:
清单 3. 配置安全资源
<!-- configurations for BASIC Authentication --> <security-constraint> <web-resource-collection> <web-resource-name>All Web services Endpoints</web-resource-name> <url-pattern>/services/*</url-pattern> </web-resource-collection> <auth-constraint> <description>Web services invokers are allowed doing invocation</description> <role-name>WsInvokerRole</role-name> </auth-constraint> </security-constraint> <!-- authentication method --> <login-config> <auth-method>BASIC</auth-method> <realm-name>Realm of Web services Invokers</realm-name> </login-config>
在“<security-constraint>”片段内,定义了改 Web Application 需要保护的资源,可以通过“<url-pattern>”来定义符合一定 URL 样式的资源,上述片段的定义,保护了所有 Web services 的 endpoints。
“<login-config>”片段定义了采取 BASIC 认证方式,其中“<realm-name>”只在 BASIC 认证方式下有效,它分配安全领域名,此名称供浏览器用于对话框标题,且为 Authorization 头部的一部分。
- 重启 Tomcat,骤重新测试该 Web Service,将有如图 7 提示框,提示输入用户名和密码:输入之前所定义的 wsaxis 用户名及其密码后,点击 OK,Web services 将会被调用。否则将无法正常调用到 Web Service。
图 7. 信息输入对话框
测试 Tomcat 下 Basic Authentication
通常 Web services 可以有两种调用方式,即静态调用方式和动态调用方式。下面将分别介绍如何使用这两种方式验证 Basic Authentication 是否正常工作。
静态调用方式测试
首先,新建一个 Java Project,命名为“TomcatAxisClient”, 如图 8
图 8. 创建 Web services 测试客户端工程
其次,将前文所声称的 Web services 的 WSDL 的 URL 作为参数,生成 Web services 客户端,如图 9
图 9. 生成 Web services Client
完成上述操作后,将有如下结构的 Web services 客户端类生成,如图 10 所示:
图 10. 生成结果
使用上述客户端类,就可以实现 Web services 的调用。现在,需要创建一个测试类,实例化客户端类,调用 Web Service。类名为“sample.test.client.runable.StaticClientTest”,详细代码见清单 4.
清单 4. 静态调用类
package sample.test.client.runable; import java.net.URL; import sample.test.ServiceImplServiceLocator; import sample.test.ServiceImplSoapBindingStub; public class StaticClientTest { public static void main(String[] args) { try { // String userName = "wsaxis", password = "wsaxis"; int addend = 64, augend = 128; ServiceImplSoapBindingStub sisbs = new ServiceImplSoapBindingStub( new URL( "http://localhost:8080/TomcatAxis/services/ServiceImpl"), new ServiceImplServiceLocator()); // sisbs.setUsername(userName); // sisbs.setPassword(password); System.out .println("Static Client Invocation:\n\tThe summation is: " + sisbs.sum(addend, augend)); } catch (Exception e) { e.printStackTrace(); } } }
运行上述代码,你将发现 Web services 不能够被顺利调用,此处将会抛出 Web services 调用异常,如图 11 所示:
图 11. 未认证时执行结果
这个错误表明,你所调用的资源是受保护的,你必须提供相关的认证信息来访问它们。如果把如下代码的注释符去掉,
// String userName = "wsaxis", password = "wsaxis"; … … // sisbs.setUsername(userName); // sisbs.setPassword(password);
再重新编译,运行,你就能得到正确的结果,如图 12
图 12. 认证后执行结果
由于 Web services 的 endpoint 被列为受限资源,需要使用这些资源,必须提供相应的认证信息。清单 4 中被注释掉的内容,正是用来向服务器认证时使用的,由于服务器无法获得认证信息,就返回了 401 Unauthorized 错误。去掉注释后的请求得到了服务器的认证,因而能够得到正确的结果。
动态调用方式测试
动态调用方式不需要生成 Web services 客户端,通过查找 Web services 提供的服务,就能调用 Web Service,此处不对动态调用方式详加解释, 清单 5 是使用动态调用的方式测试 Basic Authentication 的。
清单 5. 动态调用测试代码
package sample.test.client.runable; import javax.xml.namespace.QName; import javax.xml.rpc.Call; import javax.xml.rpc.ParameterMode; import javax.xml.rpc.Service; import javax.xml.rpc.ServiceFactory; public class DynamicClientTest { public static void main(String[] args) { try { String address = "http://localhost:8080/TomcatAxis/services/ServiceImpl"; String namespaceURI = "http://test.sample"; String serviceName = "ServiceImplService"; String portName = "ServiceImpl"; String operationName = "sum"; String userName = "wsaxis", password = "wsaxis"; int addend = 64, augend = 128; ServiceFactory factory = ServiceFactory.newInstance(); Service service = factory.createService(new QName(serviceName)); Call call = service.createCall(new QName(portName)); call.setTargetEndpointAddress(address); QName intQName = new QName("http://www.w3.org/2001/XMLSchema","int"); call.setOperationName(new QName(namespaceURI, operationName)); call.addParameter("addend", intQName, ParameterMode.IN); call.addParameter("augend", intQName, ParameterMode.IN); call.setReturnType(intQName); call.setProperty(Call.USERNAME_PROPERTY, userName); call.setProperty(Call.PASSWORD_PROPERTY, password); Object[] inParams = new Object[2]; inParams[0] = new Integer(addend); inParams[1] = new Integer(augend); int value = ((Integer) call.invoke(inParams)).intValue(); System.out.println("Dynamic Client Invocation:\n\tThe summation is: " + value); } catch (Exception e) { e.printStackTrace(); } } }
需要指出的是,与静态调用方式不同,动态调用方式设置认证的用户名和密码是通过 Property(属性)来设置的(代码中加粗的部分)。上述代码的运行结果如图 13 所示:
图 13. 动态调用测试结果
如果去掉清单 4 中加粗的部分,同样服务器将返回 401 Unauthorized 错误。
下面,本文将结合 Rational Application Developer Standard Edition Version 8.0 和 WebSphere Application Server Version 7.0 来介绍如何在 WAS 上配置 HTTP Basic Authentication,并使用 JAX-WS 实现的 Web services 加以测试。
WAS 下配置 HTTP Basic Authentication
使用 RAD 开发 Web services Provider 应用
首先,如同第 3 节中所述,在 Rational Application Developer(以下简称 RAD)中创建一个 Dynamic Project,此处需要注意,由于 RAD 中所使用的 WAS 只能部署 Enterprise Application Archive(EAR),因此,需要创建相应的 EAR 工程,并把所创建的 Dynamic Web Project 座位该 EAR 的模块。如图 14 所示:
图 14. 创建动态 WEB 工程
等待工程创建完毕之后,将有如图 15 所示的目录结构:图中高亮的两个工程是上述步骤所创建的。
图 15. 工程结构
接下来,我们仍然采用“Bottom up Java bean Web Service”方式创建用于测试的 Web Service:
- 创建 Web services 的实现类,并将如下代码复制并覆盖所创建的文件,如清单 6。
清单 6. Web services Provider 实现代码
package sample.test.jaxws; public class JaxWsServiceImpl { /** * return the summation of the two integer arguments * * @param addend * @param augend * @return */ public int sum(int addend, int augend) { return addend + augend; } }
- 使用该文件,创建 Web Service,在创建过程中,需要指定所采用的 Web services 运行时为“IBM WebSphere JAX-WS”,如图 16 所示
图 16. 创建 Web services Provider
- Web services 创建完毕后,将会被自动发布到 WAS 上,使用 Web services Explorer 加以简单测试,以便检查 Web services 是否能够被访问调用等。
配置 Web services Provider 应用的受限访问资源
此处,我们需要仿照上文为 Web services Provider 应用配置安全性,将 Web services 的 endpoint 作为受限资源,定义在应用的部署描述符(web.xml)中。
- 打开 web.xml 文件,切换到 Design 页面,如图 17 所示
图 17. web.xml 编辑页面
- 点击“Add …”按钮,在弹出的窗口中选择“Security Role”,确认后,对“Role Name”和“Description”赋值,其中“Role Name”是必填项,如图 18 所示
图 18. 添加安全角色
- 仿照步骤 2,添加“Security Constraint”项,展开“Authorization Constant”,点击“Add”按钮,添加一个 Role,名称为之前所创建的 Role:“wsRole”,继续配置 Security Constraint,将 Web services 的 endpoint 加入到受限资源中。配置完成后,如图 19 和图 20 所示:
图 19. 添加受限资源
图 20. 添加受限资源 2
- 仿照步骤 2,添加“Login Configuration”,在“Authentication Method”中输入“BASIC”,如图 21 所示
图 21. 配置认证方式
至此,Web services Provider 的受限资源以及应用的 Basic Authentication 都配置完毕。如果需要 Basic Authentication 起作用,还必须启用 WAS 的安全设置,下面我们将简要讲述如何启动 WAS 安全。
配置 WAS 安全
- 打开到 WAS 的控制台,如图 22 所示
图 22. WAS 控制台
- 登录后,选择“Security – Global Security”菜单,并点击“Security Configuration Wizard”按钮,如图 23 所示
图 23. 配置 WAS 安全 1
- 在 Wizard 的步骤 2 中,选择“Federated repositories”作为资源库。点击“Next”,输入用户名密码,并确认密码,如图 24 所示。其中,用户名和密码将作为登录控制台的用户名和密码,此处,所输入的用户名和密码都是“jaxws”。完成向导后,保存所做的修改,并重新启动 WAS。
图 24. 配置 WAS 安全 2
- 重新登录控制台,此时,将提示你输入用户名和密码,如图 25 所示:
图 25. 配置 WAS 安全 3
部署 Web services Provider 应用
在启用了安全的 WAS 上部署步骤创建的 Web services Provider 应用。
首先,在 RAD 中,将所创建的工程导出为 EAR 包;
其次,部署所导出的 EAR 到 WAS 中,具体步骤如下:
- 登录 WAS 控制台,并打开“Applications - Application Types - WebSphere enterprise applications”;
- 点击“Install”按钮,在“Preparing for the application installation”页面,点击“Browse”按钮,浏览到已经导出的 EAR 文件,并单击“Next”,如图 26 所示
图 26. 部署 Web services Provider 到 WAS 1
- 在新页面中选择“Detailed”选项,如图 27,单击“Next”
图 27. 部署 Web services Provider 到 WAS 2
- 单击链接“Step 8”,在 RAD 中所创建的 Role 和 WAS 中用户或组之间建立关联,如图 28 所示:
图 28. 建立角色 ( 用户 ) 关联
- 完成向导,并启动该 Web services Provider,如图 29 所示:
图 29. 启动 Web services Provider 应用
至此,JAX-WS Web services Provider 的 Basic Authentication 已经配置完毕,下一节,将将输入和采用静态和动态调用方式测试它。
测试 WAS 下 Basic Authentication
静态调用方式测试
如同测试 Tomcat 上的 Basic Authentication 类似,需要在 RAD 中创建一个 Java Project,利用之前所创建的 Web services Provider 提供的 WSDL 文件,创建 Web services Client,需要指出的是,Web services 的运行时需要指定为“IBM WebSphere JAX-WS”。生成客户端之后的 Java Project 的目录结构如图 30 所示
图 30. 创建测试工程
创建一个测试 Class,命名为“sample.test.jaxws.client.runable.StaticClientTest”,其内容如清单 7 所示:
清单 7. 静态测试代码
package sample.test.jaxws.client.runable; import javax.xml.ws.BindingProvider; import sample.test.jaxws.JaxWsServiceImplPortProxy; public class StaticClientTest { public static void main(String[] args) { String userName = "jaxws", password = "jaxws"; JaxWsServiceImplPortProxy proxy = new JaxWsServiceImplPortProxy(); BindingProvider bp = (BindingProvider) proxy._getDescriptor() .getProxy(); bp.getRequestContext().put(BindingProvider.USERNAME_PROPERTY, userName); bp.getRequestContext().put(BindingProvider.PASSWORD_PROPERTY, password); System.out.println(proxy.sum(123, 312)); } }
运行该测试 Class,将得到如图 31 所示的结果:
图 31. 测试结果
如果将“userName”或“password”赋予了其他的值,运行测试 Class,将得到 401 Unauthorized 错误,如图 32 所示:
图 32. 未加认证的测试结果
动态调用方式测试
使用动态调用方式测试该 Web Service,需要基于 JAX-WS 的 API 开发客户端代码,本文给出测试需要 BASIC Authentication 认证的 Web services 的样例代码,如清单 8 所示:
清单 8. 动态测试代码
以下是该样例代码的执行结果,如图 33 所示
图 33. 动态测试结果
通常,如果我们可以使用 Eclipse 或者 RAD 自带的 Web services Explorer 等测试工具来对 Web services 做简单的测试,或者,我们通过客户端来测试所开发的 Web services Provider。这样的测试通常只能发现简单而明显的问题,如何对 Web services Provider 做系统的测试呢? soapUI 这个工具能帮我们更加方便,更加系统地测试 Web services Provider。下面,我们将概述如何使用 soapUI 来测试 Web services 的 BASIC Authentication。
使用 SOAPUI 测试配置了 Basic Authentication 的 Web Service
soapUI 的是世界领先的 SOA 和 Web services 的测试工具。凭借其易于使用的图形界面和企业级功能,soapUI 能让你轻松,快速的创建和执行自动化测试,回归和负载测试。
首先,需要从 soapUI 的 官方网站 下载最新的 soapUI 安装文件,安装 soapUI。
其次,创建一个 soapUI 测试工程,提供被测试 Web services 的 WSDL 以便创建测试用例。如图 34 所示
图 34. soapUI 新建工程
如果选择了“Create Test Suite”,soapUI 将根据 Web services 的 operation 创建测试用例,同时,你还可以创建相关的性能测试用例,如图 35 所示
图 35. 生成测试集合
图 36 给出了所创建的测试工程,打开测试用例,可以看出,屏幕被分割成 3 个区域,在区域 A 中,显示了所创建的功能性测试用例和用于测试 Web services 性能的 Load Test 用例。区域 B 是 Web services 请求的配置区域,此处可以设置 Web services 使用的参数,认证等相关的信息。B 区中,红方格中的 Username 和 Password 正式设置 BASIC Authentication 使用的用户名和密码的。区域 C 是 Web services 请求返回(Response)显示区域。
图 36. soapUI 布局
然后,在区域 B 中,给 Web services 所使用参数赋值,并点击 B 区上方的“ ”按钮,如图 37 所示。
图 37. 运行测试
此时,由于没有设置相关的认证信息,将会得到图 38 所示的相关错误信息。
图 38. 未认证时 soapUI 测试结果
在 B 区域红方格所示区域中输入认证信息,再重新执行测试用例,将得到如图 39 所示的结果。
图 39. soapUI 添加认证信息
以上就是如何使用 soapUI 来测试 Web services BASIC Authentication 的步骤,从中我们可以发现,只需要简单的操作便可以实现 Web services 的测试,因此,soapUI 对于提供 Web services 的测试效率是有帮助的。