Ingo rammer consultants and developers with unique insights
September 2003
Applicable:
Microsoft. NET Framework
Web Services enhancements 2.0 for Microsoft. NET
WS-Policy Specification
Abstract:This section describes how to use Web Services enhancements 2.0 for Microsoft. NET (WSE 2.0) to integrate X.509-based WS-Security Authentication and role-based security functions in Microsoft. NET Framework. This section focuses on how to use WS-policy in WSE 2.0 to greatly simplify tasks.
Download the sample code from Microsoft download center ). (Note that in the example file, the comments of programmers are in English. In this document, the comments are translated into Chinese to facilitate your understanding .)
Directory
Introduction
Quick routing of signed emails
Use declarative and imperative role-based security
Implement identity and principal
Combine all functions
Only one line of code is required
Introduction
Microsoft. NET Framework and Microsoft ASP. NET provide many functions to protect code security. If you only useHttpcontext. Current. User. isinrole ()Similar structures can protect access to WSE-based Web service methods. Isn't that good? This article describes how to combine the mail signature and verification functions in WSE 2.0 with the role-based permission mechanism in. NET Framework.
In conventional Web applications or web services, you can use only IIS (SSL) Verification and encryption methods. In this case, you can configure the directory as follows: require users to use basic HTTP security settings or Windows integrated security settings to send logon creden。 over HTTP.
At the beginning, it seemed a good way to use HTTP to verify Web Service requests, but with the emergence of WS-routing, the situation has changed essentially: there is no direct HTTP connection between the sender of the mail and the final recipient, but different protocols may be used in this routing path. This makes all the security measures on the transport layer a purely optional addition, but does not guarantee the integrity and security of the Message end-to-end.
One way to provide comprehensive end-to-end services for Web Services is to sign emails using X.509 certificates according to WS-Security specifications.
Quick routing of signed emails
You can use a famous Certificate Authority (CA) such as Verisign to obtain an X.509 certificate, or use Windows Certificate Services to create your own ca. After installing this service as an optional component of Windows 2000 Server or Windows Server 2003, you can direct the browser to http: // <servername>/certsrv to request the creation of a new certificate. After your request is authorized by the system administrator, you can use http: // The same web application in <servername>/certsrv adds the newly created certificate to your private certificate storage. Make sure that the root certificate of the Certificate Authority is added to the local computer storage of your Web server by manually selecting the storage location (including the "physical location") When importing the certificate.
After creating and obtaining the X.509 Certificate, you can use it to sign your web service requests. However, please wait. you must first make your project Support Web Services enhancements 2.0. To. Net developer(. NET Developer) after WSE 2.0 is installed, right-click any project in Visual Studio. NET and selectWSe settings 2.0(WSE settings 2.0) Open the dialog box shown in 1.
Figure 1: Enable Web Services enhancements 2.0
After the check box is selected, many interesting events will occur. First, the reference pointing to Microsoft. Web. Services. dll will be automatically added to your project. Next, and even more importantly,Add web reference...(Add web references) andUpdate Web reference(Update web reference) The command behavior will change, allowing you to access the additional context attributes in the future. This allows you to change the security token. This is done by creating a second proxy for each web reference. The new proxy name will be suffixed with "WSE" (for example, the proxy "myservice" name is "myservicewse"), and the framework will select a different base class for it: non-WSe proxy inheritanceSystem. Web. Services. Protocols. soaphttpclientprotocolDifferent, WSE proxy will expandMicrosoft. Web. Services. webservicesclientprotocol.
With this new base class, you can now accessSoapcontextAnd can add and sign the WS-Security token for the mail to be sent. To further describe the role-based security Extension function, a demo service is created as follows:
using System;using System.Web.Services;using System.Security.Permissions;[WebService(Namespace="http://schemas.ingorammer.com/wse/role-based-security-extensions/2003-08-10")]public class DemoService: System.Web.Services.WebService{[WebMethod]public string HelloWorld(){return "Hello World";}}
Then, a Web reference is added to the project to specify itsURL BehaviorFor "dynamic", and the following APP. config file is created to specify the server location and the certificate that the customer should use. If you follow this example on your computer, please note that you must specify a certificate name in your private certificate store!
<configuration><appSettings><add key="RoleBasedSecurityClient.demosvc.DemoService"
value="http://server/WSEDemo/DemoService.asmx"/> <add key="CertificateName" value="user1@example.com"/>
</appSettings></configuration>
Web Services enhancements 2.0 can now be used to create Binary security tokens Based on X.509 certificates. This token will be appended to the mail to be sent and used to encrypt and sign the mail. In the following client code, the added functions include accessing the user's private certificate storage and searching for the certificate specified in the preceding configuration file.
Public static void main (string [] ARGs) {string sto = x509certificatestore. mystore; // open the certificate store X509CertificateStore store = X509CertificateStore.CurrentUserStore(sto);
Store. openread (); // find the certificate to use String certname = System.Configuration.ConfigurationSettings.AppSettings["CertificateName"];
X509CertificateCollection certcoll = store.FindCertificateBySubjectString(certname);
If (certcoll. count = 0) {console. writeline ("certificate not found");} else {x509certificate Cert = certcoll [0]; demoservicewse SVC = new demoservicewse (); soapcontext CTX = SVC. requestsoapcontext; // use this certificate to sign the email SecurityToken tok = new X509SecurityToken(cert);
ctx.Security.Tokens.Add(tok);
ctx.Security.Elements.Add(new Signature(tok));
// Call the Web Service string res = SVC. helloworld ();} console. writeline ("done"); console. Readline ();}
Okay! The shortcut routing of signed mail is introduced here. For more information about this path, see the article "WS-Security Authentication and digital signatures with Web Services enhancements" in Matt Powell ).
Use declarative and imperative role-based security
Great-the email has been signed. What do we do now? You can access the security token and[Webmethod]While checking whether it matches the certificate required when calling the service. Although this seems useful at the beginning, you must consider that your application needs to support a large number of users, and each user will have their own certificate. If your web service structure is more complex than the preceding simple example, you may also have users with different roles. Each role has different permissions so that some methods can only be called by users of a specific role.
When implementing traditional HTTP-based Web applications, you can accessHttpContext
To check the membership of the Windows user group or active directory group, as shown below:
[Webmethod] public void authorizeorder (long orderid) {If (! HttpContext.Current.User.IsInRole(@"DOMAIN\Accounting")
) Throw new exception ("only members of 'account' may call this method."); //... update database}
This syntax also allows you to check smaller permission groups, for example, permission groups dependent on some parameter values. In the following example, the "HR" Role user can call this method, but only the members of the "pointyhairedboss" role can set a salary value higher than a specific amount:
Public void setmonthlysalary (long employeeid, double salary) {If (! HttpContext.Current.User.IsInRole(@"DOMAIN\HR")
) Throw new exception ("only members of 'hr' may call this method."); If (salary> 2000) {If (! HttpContext.Current.User.IsInRole(@"DOMAIN\PointyHairedBoss")
) Throw new exception ("only the pointy haired boss might set salaries larger than 2 K");} //... update database}
The above Code depends on a standard ASP. net function-although only one, it is a serious defect for our solution: in fact, it cannot meet the requirements of the end-to-end authentication solution, because it depends on HTTP authentication. The second point is that a user's role member identity is determined by viewing the member identities of the windows or active directory group. This will lead to the need for a large number of windows groups whenever the application requires a detailed permission level. This will cause a headache for the system administrator.
Provides a custom security token manager for the solution
Fortunately, WSE 2.0 provides the necessary scalability hooks for you to implement role-based security. The corresponding operation is simpler: you only need to provide necessary information to the runtime to determine the user's role member identity. Otherwise, how does the framework know that someone who belongs to the pointyhairedboss role has sent an email with the signature "user1@example.com?
In this case, to enable role-based security, you can writeMicrosoft. Web. Services. Security. tokens. x509securitytokenmanagerDerived custom security token manager. The new token manager will be displayed later. It will read a configuration file similar to the following to determine the ing between the certificate and the role:
<?xml version="1.0" encoding="utf-8" ?><CertificateMapping><Certificates><!-- user1@example.com --><CertificateMap Hash="f5 06 ba 1d 76 3b 59 1f ac 0c 3d ff e8 52 a3 41 44 b5 ed b1"><Roles><Role>PointyHairedBoss</Role><Role>Accounting</Role><Role>HR</Role></Roles></CertificateMap><!-- user2@example.com --><CertificateMap Hash="d7 fd 06 0d 43 7f 8f bb df a2 ee 9a 55 e4 c4 49 93 65 99 e4"><Roles><Role>Accounting</Role><Role>HR</Role></Roles></CertificateMap></Certificates></CertificateMapping>
In this configuration file, each certificate for the role to be specified corresponds to one<Certificatemap>. The certificate is identified by the special hash code. You can use the Windows Certificate Services management tool to obtain the hash code. The management tool is located at the start by clicking "start">Administrative Tools(Management tools)>Certification Authority(Ca. When you run the tool and select a previously issued certificate, you will see the window shown in 2, allowing you to copy the hash code to the clipboard.
Open Internet Explorer and click "Tools"> "Internet Options"> "content"> "certificate". You can also access this information for all certificates in the current user's certificate store.
Figure 2: certificate details
Then, you can use the hash code to create a new<Certificatemap>To specify the role associated with the given certificate. This file will beXmlserializerRead, restore and serialize based on the following two classes, and transfer them to the object:
public class CertificateMapping{[XmlArrayItem(typeof(CertificateMap))]public ArrayList Certificates = new ArrayList();public CertificateMap this[String hash]{get{foreach (CertificateMap cert in Certificates){if (cert.CertificateHash.Replace(" ","").ToUpper() == hash.ToUpper())return cert;}return null;}}}public class CertificateMap{[XmlAttribute("Hash")]public String CertificateHash;[XmlArrayItem("Role", typeof(String))]public ArrayList Roles = new ArrayList();}
Introduction to x509securitytokenmanager
The token manager must inheritMicrosoft. Web. Services. Security. tokens. x509securitytokenmanager
. After registering this class with the framework, eachX509The binary Security token inAuthenticatetoken ()Method verification before arriving[Webmethod]. Therefore, this method allows you to create a matchedIprincipalObject used to hook back to the. NET security model.
To implement the security token manager, you must first Add a reference for the required namespace:
using System;using System.Collections;using Microsoft.Web.Services.Security;using Microsoft.Web.Services;using Microsoft.Web.Services.Security.Tokens;using System.Security.Principal;using System.Threading;using System.Xml.Serialization;using System.IO;using System.Web;using System.Security.Permissions;
Then overwriteAuthenticatetoken ()Method to access the passed Security token and append a matchedIprincipal.
namespace RoleBasedSecurityExtension{[SecurityPermission(SecurityAction.Demand,Flags=SecurityPermissionFlag.UnmanagedCode)]public class X509RoleBasedSecurityTokenManager: X509SecurityTokenManager{protected override void AuthenticateToken
(X509SecurityToken token){base.AuthenticateToken(token);token.Principal = new CertificatePrincipal(token.Certificate);
}}}
Implement identity and principal
The role-based security function of. NET Framework is based onPrincipalAndIdentityThe object is specified based on the request context. The principal object contains the role of the current user. the identity object stores information about the user and its authentication.
These two interfaces can beSystem. Security. PrincipalAnd their contents are as follows:
public interface IPrincipal{IIdentity Identity { get; }bool IsInRole(string role);}public interface IIdentity{string AuthenticationType { get; }bool IsAuthenticated { get; }string Name { get; }}
To complete role-based security extension, this article implements a custom principal object (CertificateprincipalAnd a custom identity object (CertificateidentityTo access the role Member identity of the current user and to access the certificate used for authentication.
When an incoming email arrives at the server, the security token manager calls the public constructor of this class andX509certificateObject as a parameter. If the role ing has been changed, this class loads the role ing from the XML file or uses the cached file stored in the static variable. Then, the filter finds the given certificate in the Information loaded from the XML file. Check whether the role Member identity information for the given certificate has been recorded. If not, an exception is thrown; otherwise, a corresponding identity object is created.
To implement a principal object, you must first include the necessary namespace:
using System;using System.Xml.Serialization;using System.IO;using System.Security.Principal;using Microsoft.Web.Services.Security.X509;
If necessary, the public constructor reads the XML file and checks whether the sender certificate has been configured in certmap. config. If it has been configured, a newCertificateidentityObject. Otherwise, an exception is thrown.
Public class certificateprincipal: iprincipal {Private Static certificatemapping _ map; Private Static datetime _ certmapdatetime = datetime. minvalue; private certificatemap _ certmap; private certificateidentity _ ident; Public certificateprincipal (x509certificate CERT) {string file = system. web. httpcontext. current. server. mappath ("certmap. config "); // compare the date fileinfo F = new fileinfo (File) between the file and the cached file; datetime filedate = f. lastwritetime; // if necessary, reload if (filedate> _ certmapdatetime) {xmlserializer SER = new xmlserializer (typeof (certificatemapping); Using (filestream FS = new filestream (file, filemode. open, fileaccess. read) {_ map = (certificatemapping) Ser. deserialize (FS);} _ certmapdatetime = filedate;} _ certmap = _ map [cert. getcerthashstring ()]; If (_ certmap = NULL) {Throw new applicationexception ("the Certificate" + cert. getcerthashstring () + "has not been configured. ");} _ident = new CertificateIdentity(cert);
}
The principal implementation also provides a method for accessing the role Member identity configured in the XML file and a method for retrievingIdentityObject Attributes:
public bool IsInRole
(string role){return _certmap.Roles.Contains(role);}public System.Security.Principal.IIdentity Identity{get{return _ident;}}}
CertificateidentityClass inclusionIidentityIs used to accessX509certificateObject.
public class CertificateIdentity: IIdentity{private X509Certificate _x509cert;internal CertificateIdentity(X509Certificate cert){_x509cert = cert;}public bool IsAuthenticated{get{return true;}}public string Name{get{return _x509cert.GetName();}}public string AuthenticationType{get{return "X.509";}}public X509Certificate Certificate{get{return _x509cert;}}}
Combine all functions
The last step to complete the required functions is to use the server application to register the newly created token manager. After Web Services enhancements 2.0 is installed, you can perform this operation in two different ways. You can directly edit the Web. config file or use the WSE 2.0 setting tool described in Figure 1.
To use the WSE 2.0 setting tool in Visual Studio. NET, right-click a Web Service Project and selectWSe settings 2.0(WSE setting 2.0 ). The dialog box shown in 3 is displayed. Make sure that both check boxes are selected.
Figure 3: WSE and extended processing process for enabling web service projects
SwitchSecurity(Security) tab to specify the name of the token manager, as shown in 4.
Figure 4: Add a new token manager and verify the certificate settings. (Click to view the large image .)
To add a new token manager, clickAdd...(ADD) and fill in data, as shown in Figure 5. Please note that,Type(Type) items must be specified in the following format:
<Namespace>.<Classname>,<Assemblyname>
This makes the full type of the example named "rolebasedsecurityextension. x509rolebasedsecuritytokenmanager, rolebasedsecurityextension ".
Figure 5: Add a new token Manager
The last step is inPolicyConfigure the policy file on the (policy) tab, as shown in figure 6. We will immediately see the contents of this policy file.
Figure 6: Set the policy file name (click to view the large image .)
The security token manager, policy file, custom principal, and identity object are combined to allow you to use WS-policy to use role-based security in a descriptive form.
Only one line of code is required
The beginning of this article shows you the traditional ASP.. Net Applications Use Role-based security in two different ways: one is to check the role based on explicit code, and the other is to use. to specify the security requirements of a method.
There are two similar methods in the Web service application that enables WSE 2.0. The main difference is that we do not use the. NET attribute to specify the security needs of the method, but rely on the WS-policy function. The reason for this is that this policy has an unparalleled advantage: it is an XML file that can be handed over to developers who want to implement the client program. In this way, developers can determine the requirements to be met for each Web Service in advance.
However, let's start with the code based on the role Member identity check. UnfortunatelySomecontext. Current. User. isinrole ()The Simple Method of structure is no longer available, because multiple security tokens may exist in the incoming soap mail. In this article, two auxiliary methods are provided. The first method is to check the security context of the current request and find the x509securitytoken used to sign all the body of the incoming mail. The second auxiliary method is a small package, which providesSomecontext. Current. User. isinrole ()A simple programming interface.
public X509SecurityToken GetBodySigningToken
(Security sec){X509SecurityToken token = null;foreach (ISecurityElement securityElement in sec.Elements){if (securityElement is Signature){Signature sig = (Signature)securityElement;if ((sig.SignatureOptions & SignatureOptions.IncludeSoapBody) != 0){SecurityToken sigToken = sig.SecurityToken;if (sigToken is X509SecurityToken){token = (X509SecurityToken)sigToken;}}}}return token;}private bool CurrentCertificatePrincipalIsInRole
(String role){X509SecurityToken tok = GetBodySigningToken(RequestSoapContext.Current.Security);if (tok == null) return false;if (tok.Principal == null) return false;return tok.Principal.IsInRole(role);}
Now, you only need to use a line of code to check the role membership of the sender's X.509 Certificate.[Webmethod]Using these auxiliary methods:
[Webmethod] public void setmonthlysalary (long employeeid, double salary) {If (! CurrentCertificatePrincipalIsInRole ("HR")
) Throw new exception ("only members of 'hr' may call this method."); If (salary> 2000) {If (! CurrentCertificatePrincipalIsInRole("PointyHairedBoss")
) Throw new exception ("only the pointy haired boss might set" + "Salaries larger than 2 K");} //... actual work is deleted ...}
No wizard?
What is missing is that the policy file is used to specify the security requirements of Web Services in a declarative manner. In today's Web service field, this is where WSE 2.0 can clearly provide the best support for all available tools! You can use the WSE settings 2.0 dialog box again instead of manually writing the policy file according to WS-policy. In this dialog box, switchPolicy(Policy) tab, and clickCreate/edit(Create/edit), and then clickAdd Policy(Add Policy) Open the dialog box 7.
Figure 7: adding a policy is easier!
As you can see in this dialog box, the only task you need to do is to use WS-policy-based declarative security to specify the service location, selectRequire signature(Signature required) check box, select the signature type, and enter the role required to access the service.
These settings enable the Framework to check all incoming emails according to the security requirements specified in the policy file. For example, if the incoming mail is not signed or the certificate is not assigned to the "accounting" role, a soap error is returned to the client informing the incoming mail that it does not comply with the policy requirements. Note: If you receive an exception notifying that the trust chain of the certificate cannot be verified, the root certificate of your custom Certificate Authority has not been installed in the local computer storage. To solve this problem, go to http: // <your_certificate_server>/certsrv and manually select the import location and physical import location in the import certificate Wizard to import the root certificate.
Summary
This article describes how to create and use Web Services enhancements 2.0 for Microsoft.. Net custom security token manager to check X.509 certificates, map them to roles, and fill context information with custom principal and identity objects. In addition, it illustrates how easy it is to use the WS-policy of Visual Studio. NET to add declarative checks of role membership to your application. Compared with traditional HTTP-based security, this WS-Security-based method has the advantage that it does not depend on the integrity and security of the transport layer, but is only implemented by soap mail. This provides end-to-end security functions for multi-hop and multi-protocol scenarios.
Author Profile
Ingo Rammer is a consultant, mentor, and developer with unique insights. It helps a number of software development and telecommunications companies adopt Microsoft. NET and Web Service technologies. He helped many Fortune 500 companies and independent software developers (ISVs) in Europe and North America to transition to. net. In addition to the consultancy service, he is also a lecturer at developmentor and a distinguished speaker from the Developers Association all over the world. In addition, he has written two best-selling books, advanced. net remoting and advanced. net remoting in VB.. Net (apress ). Ingo is Microsoft regional ctor in Austria. For more information, visit the http://www.ingorammer.com/(English ).