WSE 3.0 UsernameToken应用

    通过这篇文章的步骤可以比较详细的了解如何在Web Service中使用WSE 3.0的UsernameToken,通过这个例子,也能够大致了解WSE 3.0的工作方式。
    1. 在配置中定义安全策略(Policy),然后在Web Service中运用安全策略非常简单方便。产品发布之后,通过修改安全策略的配置文件,可以满足不同的安全应用要求,而不需要修改代码。
    下面示例在Web Service端定义了一个名称为ServerPolicy的安全策略,通过给Web Service的类MyService添加Attribute [Policy("ServerPolicy")]应用这个安全策略;在客户端定义的名称为ClientPolicy,通过 serviceProxy.SetPolicy("ClientPolicy");这个语句在客户端应用这个安全策略。在开发过程中,WSE 3.0的应用就这么简单。
    2. WSE 3.0跟.Net Framework的Web Service整合在一起。
    客户端请使用带Wse后缀的那个Proxy。客户端发送Web Service调用请求的时候,WSE插入一些Filter,对即将发送的SOAP消息进行一些处理,例如签名、加密等。服务器端Web Service调用请求后,WSE同样插入一些Filter先对消息进行解密、签名的验证等。这些都由WSE自动完成,对Web Service的开发不会造成任何影响以及带来额外的代码工作,并享受WSE带来的安全性。
    3. 其他的一些特性,例如方便的添加用户自定义的安全断言;大数据量MTOM的支持;使用TCP方式传输SOAP消息,从而使Web Service可以脱离Http Server;SOAP消息的路由等。

    测试环境:
    一台Server机器A用于Host Web Service,一台Client机器B用作客户端调用。两台机器都都处在Windows域环境中(内网),访问外网需要代理+域身份认证,域内的安全策略比较严格。
    为了使用WSE 3.0,机器A和B都必须安装有.Net Framework 2.0以及SDK。在机器A上,请将Framework 2.0 SDK安装目录\v2.0\Bin路径加入到Windows的Path环境变量中。
    WSE 3.0下载地址。下载并安装WSE 3.0,在机器A上必须安装Tools和Samples,如果作为开发环境最好是选择跟Visual Studio 2005整合方式(机器A是我的开发环境,下面示例的开发都是在机器A上完成),这样开发过程中配置WSE 3.0比较方便,在机器B上安装WSE 3.0 Runtime就可以了。

    1. CA证书安装
    WSE 3.0中UsernameToken需要跟一个服务器端的X.509 Certificate结合使用,下面的步骤在机器A上创建这个服务器端证书。
    下面的批处理脚本在机器A上创建一个测试用的证书MyServiceCert并作一些配置。将脚本保存到一个.bat文件中,将文件拷贝到C:\Program Files\Microsoft WSE\v3.0\Samples目录下并运行。运行完后请确认makecert.exe这一句有执行成功。如果硬盘分区是FAT32,winhttpcertcfg执行失败没有关系,如果是NTFS,需要确保这一句操作成功。
    winhttpcertcfg是确保.Net运行帐号有权限访问证书的私匙文件以读取私匙信息,也可以使用C:\Program Files\Microsoft WSE\v3.0\Tools\WseCertificate3.exe进行配置。运行WseCertificate3.exe,Certificate Location选择Local Machine,Store Name选择Personal,然后点击Open Certificate按钮,选择MyServiceCert这个证书并确认。这时WseCertificate3.exe会加载MyServiceCert证书的相关信息,点击View Private Key File Properties按钮,弹出的实际上是私匙文件的属性对话框,如果是NTFS格式的磁盘,在文件属性对话框里会有安全这一个属性页,确保ASPNET帐号或者Network Service帐号(或者是你在ASP.NET的machine.config或Application Pool中配置的帐号)有权限访问这个文件。
    set CERTNAME=MyServiceCert
    certmgr -del -r LocalMachine -s My -c -n %CERTNAME%
    makecert.exe -sr LocalMachine -ss My -a sha1 -n CN=%CERTNAME% -sky exchange -pe
    set WP_ACCOUNT=NETWORK SERVICE
    (ver | findstr "5.1") && set WP_ACCOUNT=%COMPUTERNAME%\ASPNET
    winhttpcertcfg -g -c LOCAL_MACHINE\My -s %CERTNAME% -a "%WP_ACCOUNT%"
    iisreset
    pause
    接下来的步骤是把机器A的服务器端证书导出,并安装到客户端机器B上。
    在机器A上命令行运行mmc打开控制台,添加证书(英文版应当为Certificate)的管理单元,在添加管理单元时选择计算机帐户选项(英文版应当为Local Computer)。在个人->证书(Personal->Certificate)中MyServiceCert的右键菜单选择所有任务->导出,导出过程中选择不要导出私匙选项,导出格式DER、Base64等随便选择都可以,将证书导出到mss.cer文件中。
    把mss.cer文件拷贝到机器B上,同样在机器B上的mmc控制台中添加证书的管理单元,注意这次添加管理单元时选择我的用户帐户(Current User)。在个人(Personal)的右键菜单上选择导入,选择mss.cer文件。

    2. 编写UsernameTokenManager
    UsernameTokenManager用于辅助完成服务器端对客户端提交过来的用户名密码进行验证功能。 客户端用用户名、密码等信息创建UsernameToken对象,WSE通过Soap Header将相关信息传递给Web Service,Web Service接收到请求后,WSE可以从Soap Header中得到UsernameToken的相关信息并构造这个对象。我们在这一个步骤中编写的UsernameTokenManager,就是在Web Service端根据用户名去获取用户密码,并将密码返回给WSE 3.0,WSE 3.0将验证这个密码与客户端提交的密码是否一致,来完成对客户端的认证。
    新建一个Class Library的工程UsernameTokenManager,添加对Microsoft.Web.Services3.dll的引用(因为安装WSE 3.0时已经将这个dll注册到全局assembly中,因此引用的时候在.Net项中就可以找到),添加一个类MyUsernameTokenManager,类的代码如下。
using  System;
using  System.Xml;
using  System.Security.Permissions;

using  Microsoft.Web.Services3.Security;
using  Microsoft.Web.Services3.Security.Tokens;

namespace  WSETest
{
    
public   class  MyUsernameTokenManager : UsernameTokenManager
    {
        
public  MyUsernameTokenManager()
        {
        }

        
public  MyUsernameTokenManager(XmlNodeList nodes)
            : 
base (nodes)
        {
        }

        
///   <summary>
        
///  Returns the password or password equivalent for the username provided.
        
///   </summary>
        
///   <param name="token"> The username token </param>
        
///   <returns> The password (or password equivalent) for the username </returns>
         protected   override   string  AuthenticateToken(UsernameToken token)
        {
            
//  这个示例中Server与Client端只是用一个简单的约定来验证密码:密码=用户名
            
// 实际项目中一般做法是从数据库查询用户的密码,通过这个函数返回
            
// WSE 3.0用该函数返回的密码,对Client端提交过来的密码进行验证
             byte [] password  =  System.Text.Encoding.UTF8.GetBytes(token.Username);
            Array.Reverse(password);
            
return  Convert.ToBase64String(password);
        }
    }
}
    编译生成UsernameTokenManager.dll。

    3. 测试用Web Service开发与WSE 3.0配置
    a) 写Web Service。用VS2005 New一个Web Site:WSEServer,添加一个Web Service项:MyService。我们直接使用VS生成的HelloWorld()方法进行测试。为Web项目添加UsernameTokenManager.dll的引用。
    b) 启用WSE 3.0。在Web项目WSEServer右键菜单中选择WSE Settings 3.0...,在弹出的对话框中勾选上Enable this project for Web Services Enhancements和Enable Microsoft Web Services Enhancement Soap Protocol Factory。这一步骤是在WSEServer项目上启用WSE 3.0,通过这个步骤也就把Microsoft.Web.Services3.dll添加到项目的引用中了。
    c) 配置使用UsernameTokenManager。在WSE Server项目的右键菜单中选择WSE Settings 3.0...,在Security属性页添加一个Security Tokens Managers,先在Built In Token Managers中选择User Name Token Manager,然后把Type替换成WSETest.MyUsernameTokenManager, UsernameTokenManager。
    在MyService.cs代码中添加using WSETest;。
    d) 创建服务器端安全策略。在WSE Server项目的右键菜单中选择WSE Settings 3.0...,在Policy属性页选择Enable Policy,添加一个Policy命名为ServerPolicy,确定后进入WSE Security Settings Wizard。选择Secure a service application,Client Authentication Method选择Username。接下来的对话框中Perform Authorization不要勾选。随后的屏幕如下:
    WSE 3.0 UsernameToken应用

    WSE 3.0 UsernameToken应用
    e) 应用服务器端安全策略。在MyService.cs代码中添加using Microsoft.Web.Services3;。 为Web Service的类添加Attribute以应用上面定义的安全策略。
   
    f) 配置Web Service虚拟目录。在IIS中建立、配置一个虚拟目录WSEServer指向Web Service的目录,确保在机器B上能够访问到http://机器A IP/WSEServer/MyService.asmx这个Web Service。可能相关的一些设置:虚拟目录设置、防火墙设置、启用Guest帐号等。

    4. Client端开发与WSE 3.0配置
    a) 建立客户端项目。建立一个Console Application WSEClient作为客户端。在项目右键菜单选择WSE Settings 3.0... ,勾选Enable this project for Web Services Enhancements并确定。添加下面的命名空间引用。
using  Microsoft.Web.Services3;
using  Microsoft.Web.Services3.Design;
using  Microsoft.Web.Services3.Security;
using  Microsoft.Web.Services3.Security.X509;
using  Microsoft.Web.Services3.Security.Tokens;
    b) 添加Web Service引用。引用地址http://机器A IP/WSEServer/MyService.asmx,千万不能用localhost,否则在机器B上无法访问到。Web Reference Name取名为MyServiceRef。
    c) Main函数的代码。
static   void  Main( string [] args)
{
    
try
    {
        MyServiceRef.MyServiceWse serviceProxy 
=   new  WSEClient.MyServiceRef.MyServiceWse();
        serviceProxy.SoapVersion 
=  SoapProtocolVersion.Default;

        
// user name token
         string  userName  =  Environment.UserName;
        
byte [] midPassword  =  System.Text.Encoding.UTF8.GetBytes(userName);
        Array.Reverse(midPassword);
        
string  password  =  Convert.ToBase64String(midPassword);
        UsernameToken token 
=   new  UsernameToken(userName, password);
        serviceProxy.SetClientCredential(token);

        
// apply policy
        serviceProxy.SetPolicy( " ClientPolicy " );

        
// use the domain proxy for credential
        serviceProxy.Proxy  =   new  System.Net.WebProxy( " proxy server " true );
        serviceProxy.Proxy.Credentials 
=   new  System.Net.NetworkCredential( " domain account " " password " " domain name " );

        
// call web service
        Console.WriteLine( " Calling {0} " , serviceProxy.Url);
        
string  result  =  serviceProxy.HelloWorld();
        Console.WriteLine(
" Result : {0} " , result);
    }
    
catch  (Exception e)
    {
        Console.WriteLine(e.Message);
    }

    Console.WriteLine(
"" );
    Console.WriteLine(
" " );
    Console.ReadLine();
}
     上面对serviceProxy.Proxy对象的相关设置,是因为在域环境里面,如果不设置代理以及和代理相关的认证信息,调用Web Service时会有异常,异常信息为:请求因HTTP状态407失败,The ISA Server requires authorization to fulfill the request. Access to the Web Proxy service is denied. 对于Web Service和Client都在本地,或者局域网内不需要使用代理的情况下,这两行代码不需要。
    d) 创建安全策略。上面步骤中使用了一个ClientPolicy,但是还没有定义它,接下来就是定义这个安全策略。
    首先在机器A(开发环境)的命令行运行下面的命令:certmgr.exe -add -r LocalMachine -s My -c -n MyServiceCert -r CurrentUser -s AddressBook,这个命令将在步骤1中在机器A上建立的证书从Local Machine的Personal拷贝到Current User的Others下面,这是为了在下面定义客户端安全策略的时候能够选择到这个证书。
    在项目右键菜单选择WSE Settings 3.0... ,在Policy属性页选择Enable Policy,添加一个Policy命名为ClientPolicy,确定后进入WSE Security Settings Wizard。选择Secure a client application,Client Authentication Method选择Username。勾选Specify Username Token in code。接下来Message Protection的选择跟前面Web Service端的贴图完全一样。然后是选择证书,点击Select Certificate按钮后可以看到MyServiceCert的证书,这个步骤中列出的是在证书管理单元的Current User->Others->Certificates中的看到的证书列表,上面证书拷贝的命令使得在这里能够选择到这份证书。
    e) 本地测试。到现在,在开发机器A上面运行Client端,应当可以在Console窗口看到成功调用Web Service的Hello World的结果。

    5. 将Client部署到机器B上测试
    将下面几个文件拷贝到机器B的测试目录下:WSEClient.exe、WSEClient.exe.config、wse3policyCache.config,在机器B上用记事本打开wse3policyCache.config文件,将下面这一节点:<x509 storeLocation="CurrentUser" storeName="AddressBook" ... />修改成<x509 storeLocation="CurrentUser" storeName="My" ... />,保存。
    然后登陆机器B,运行WSEClient.exe,可以看到运行结果如下。
    WSE 3.0 UsernameToken应用
    第一点,在客户端机器B上部署,应当包括服务器端证书的导入,我把这个放在步骤1中了。
    第二点,集成在VS2005中的WSE 3.0配置工具,在为客户端选择X.509证书时,只能够从Local Machine或者是Current User的Others(其他人)的Store Name中选择证书,但是我看到有的机器上默认情况下这个Others的Store Name是看不到的,在控制台中也没有地方可以把它添加进来,只能够通过执行某些命令行的操作使它出现。基于这样一种情况,在上面的例子中,我在机器A上开发、配置Client时先用命令把证书拷贝到Current User的Others下,使得配置过程中能够选择到证书。而在机器B上部署测试客户端时,是将证书导入到机器B的Current User的Personal(个人)中,并修改配置文件让WSE从Personal读证书信息。

你可能感兴趣的:(token)