Tuesday, November 30, 2004
While doing some deep plumbing work, I discovered that Lutz Roeder's ultimate awesome Reflector() tool is already throwing up some wonderful Whidbey VB.NET keywords. AND I dont even have .NET 2.0 installed on that machine yet. Cool
One of the keywords used is TryCast. TryCast is a new VB.NET Keyword in VS2005 which essentially combines 2 type checks into 1. For example
If TypeOf o Is XMLElement Then 'One TypeCheck
XMLElementObj = DirectCast(o, XMLElement)...' Another Type Check
Dim XMLElementObj As XMLElement = TryCast(o, XMLElement)
Of course, performance is the differentiating issue here. TryCast, as its name suggests, will try the cast and, if it succeeds, return the value cast to that type, else, it returns nothing.
Think of it as VB.NET's answer to C# “As” keyword. Here is also a good blog about it.
Monday, November 29, 2004
Andrés G Vettori has done it again...
Saturday, November 27, 2004
Can or Should a SOAP node process multiple security headers ?
Should Trust be End-to-End or Node-to-Node ?
Tuesday, November 23, 2004
Word from the man Hervey himself. Find it here.
WSE2.0 SP2 Pre-release Full product and the Runtime
Contents from the ReadMe:
Core product changes:
- A new compatibility section is used to select the wire format on the sending
side. The mode attribute tells WSE runtime to generate a message which will be
compatibable to a particular release of WSE. By default, the mode is WSE2RTM. It can be WSE2RTM, WSE2SP1 WSE2SP2 and so on. On the receiving end, a particular version of WSE runtime will be able to accept all types of wire format in all its previous releases. In a request-response message exchange, a server will generate a response message which is compatible with the request message. The server will, by default, still use the compatibility section to generate its response if it cannot determine the compatibility mode based on the request message.
- A new implementation of the Kerberos token based on SSPI interfaces is included in this release. The new token is named KerberosToken2. Please see the reference documentation for more details.
- The TokenIssuer element in the KerberosToken security token assertion is
no longer supported on the receiving end.
- The SecurityTokenManager no longer throws exception in LoadTokenFromXml() when token.IsCurrent returns false. WSE security input filter will continue checking that and throw exception if token.IsCurrent returns false.
- The inclusion of unencrypted Username tokens in a message may represent a security vulnerability. The SecurityTokenServiceClient class will now automatically encrypt any Username tokens included in a request. Similarly, the SecurityTokenService class will automatically encrypt any username tokens included in a response.
The following methods have been added to the token issuing framework:
protected virtual void SecurityTokenServiceClient.EnforceRequestUsernameTokenEncryption().
Called from EnforceRequestPolicy(), this method enforces the requirement that any Username tokens in an RST message must be encrypted. The issuerToken is used as the encrypting token. This method will throw an exception if it cannot encrypt the UsernameTokens in an RST message.
Override this method to suppress this behavior.
protected virtual void SecurityTokenService.VerifyRequestUsernameTokenEncryption().
Called from VerifyRequestPolicy(), this method verifies that tokens in an RST message are encrypted. This method will throw an exception if it encounters an unencrypted UsernameToken in an RST message.
Override this method to suppress this test.
protected virtual void SecurityTokenService.EnforceResponseUsernameTokenEncryption().
Called from EnforceResponsePolicy(), this method enforces the requirement that any Username tokens in an RSTR message must be encrypted. The ResponseEncryptingToken is used as the encrypting token. This method will throw an exception if it cannot encrypt the UsernameTokens in an RSTR message.
Override this method to suppress this behavior.
protected virtual void SecurityTokenServiceClient.VerifyResponseUsernameTokenEncryption().
Called from VerifyResponsePolicy(), this method verifies that tokens in an RSTR message are encrypted. This method will throw an exception if it encounters an unencrypted UsernameToken in an RSTR message.
Override this method to suppress this test.
- A new method, protected virtual void SecurityTokenServiceClient.ClearRequestSoapContext(), has been added. This method was added to fix a bug in which successive requests for a SecurityContextToken, made through a single instance of SecurityContextTokenClient, would fail. The problem was caused by a failure to clear security elements and tokens from the soap context after a request was made. In the event that a sub-class of SecurityTokenServiceClient requires that security elements or tokens in the soap context be preserved from one request to another, the new behavior may be suppressed by overriding the ClearRequestSoapContext method.
- SoapService will now send back an empty SoapEnvelope back if the soap method it is invoking returns null for a request/response scenario.
- EncryptedData.Decrypt will only support decryption to one and only one xml element. It throws a security fault otherwise.
- In the SoapHttpOutputChannel.Send method, if the response has an unsupported content type, such as text/html, the response stream will be read and stored in the exception text.
- Two new properties, SimpleDisplayName and FriendlyDisplayName, have been added to the X509Certificate class.
- The default Label used in DerivedKeyToken has changed from "WS-SecureConversation" to "WS-SecureConversationWS-SecureConversation".
- If an incoming message contains multiple security tokens with envelope signature inside those tokens, the server was returning a security fault. This is now fixed.
- If WSE SOAP messaging stack is used over HTTP/HTTPS transport, a simple WSE805 exception was thrown when the response content type was not supported. Now if the response stream is readable, WSE runtime will read from response stream and throw a WSE805 exception with a more detailed error information read from the response stream.
- WSE configuration section will now allow whitespace or comments as child nodes for the following configuration elements: diagnostics/trace, diagnostics/policyTrace, diagnostics/detailedErrors, referralCache/cache, security/x509, security/limits.
- When a security context token was deserialized, WSE runtime will retrieve a token from its cache based on its globally unique Identifier. The token retrieved from the cache sometimes have a different Id than the token received from the incoming message. If that happens, WSE runtime would previously fail to verify a signature or decrypt the message. It is now fixed as it will assign the Id of the token from the incoming message to the token retrieved from the cache.
- The built-in SecurityContextToken service would previously cache a newly issued security context token instance before those properties defined in the IIssuedToken interface are set. Now it is fixed so that those properties are set before the newly issued token is cached.
- WSE runtime would previouly always generate a relative token reference in calculating message signature. When the token is not sent with the message, the receiver will return a security fault. It is now fixed so that an absolute token reference will be generated in the case when the security token is not in the message.
- A server fault was thrown previously when a server tries to verify a signature or decrypt a message based on a username token which uses plaintext password option or no password option and does not have nonce and/or created element. The exception is now changed to be a client fault.
- SoapService instances configured to automatically issue SecurityContextToken (SCT) security tokens no longer re-use the same instance of the SCT issuer. With this service pack, a new instance is created per request. This instance is accessible via the SoapService.AutoIssueSCTService property. If the old behavior
is required, there are two work-arounds:
- override the SoapService.AutoIssueSCTService property to return a singleton instance of a SecurityContextTokenService, or
- create a wrapper SecurityContextTokenService that delegates to a singleton instance and register it through configuration.
Visual Studio tool integration changes:
- The default value for http Routing handler type is updated.
- WSE setting tool can support VS C++ project.
- WSE setting tool would always prompt users for confirmation when the Cancel button was clicked. Now it is fixed so that the tool will prompt user only when some changes are made by users.
- The Security Settings Wizard can support creating Policy files for remote service.
WseWsdl2 tool changes:
- The WseWsdl2 tool now properly generates proxy classes when an Web service uses a Guid type.
- If an input schema contains a type definition which is derived from another complex type, the proxy class would generate a class definition for that derived type with incorrect namespace. This is now fixed.
I came across this blog last week, detailing a problem he is facing with WSE 2.0
Now I that realize who he is (Hello Fai ), I peep into his project to see how I could help. Fai, incidentally, is the Academic DE for MSFT Malaysia and I met him in MS Tech.ED 2004 Asia in Msia.
Since I cannot comment on this blog (since theSpoke doesnt allow it and I dont intend to keep another account), I will comment on his problem here.
I reproduce Fai's blog snippets here.
SoapSender & SoapReceiver
I've been mucking around with WSE 2.0 Messaging, now moving on to SoapSender and SoapReceiver. I noticed a potential problem when I have a class that extends the SoapReceiver class, and within the Receive() method, it also sends out a SoapEnvelope via the SoapSender.Send() method. The problem only arises when I use a real transport protocol, i.e., TCP, but not when I'm using the in-proc transport. I've tried all sort of ways, including transfering the SoapSender code away from the Receive() method to a method in another class. But it still doesn't work.
The behavior of my current Receive() method almost seems like it is acting like a SOAP router. This is because it receives a SoapEnvelope, sends out another SoapEnvelope albeit doing some computation and returning a totally different SoapEnvelope.
Then I discovered the IsIntermediary property of the Pipeline class from this blog. According to the WSE 2.0 Class Reference, this property gets or sets a value indicating whether the pipeline is running within a SOAP router. Fair enough, and I implemented the following code:
// send response SOAP message
SoapEnvelope env = new SoapEnvelope();
env.Context.Addressing.Action = e.Context.Addressing.Action;
env.Context.Addressing.Destination = e.Context.Addressing.ReplyTo;
Pipeline pipe = new Pipeline();
pipe.IsIntermediary = false;
SoapSender responseSender = new SoapSender(env.Context.Addressing.Destination);
responseSender.Pipeline = pipe;
responseSender.Destination = env.Context.Addressing.Destination;
I've also tried move the MathResponseReceiver class to a separate project so that it can be started separately. Still to no avail. According to another blog I read, WSE 2.0 is smart enough to know if there are two receivers classes within a single application domain, and both are communicating with each other using an actual network protocol like TCP or HTTP, it will detect that and switch it in-process instead.
But still it doesn't work! I appreciate if anyone out there could help me fix this. Could it be a bug in WSE 2.0?
talks about pipelines and routing in his blog above. However, I dont think the pipeline.IsIntermediary helps you in this case because you really never did subject your message through a routing pipeline. Therefore, it doesnt address or solve your problem at all.
The problem (after looking through your codes and running SOAP Trace Diagnostics) and you are going to hate me for this, is just a programmatic syntax error
env.Context.Addressing.Destination = e.Context.Addressing.ReplyTo.Address.Value;
What you missed out was actually pass in the address property of the ReplyTo class. This address property (which is inherited from an EPR) will get you the address of the destination.
So, your final code snippet should simply look like this (without the pipelines class):
SoapSender responseSender = new SoapSender(e.Context.Addressing.ReplyTo.Address.Value);
SoapEnvelope env = new SoapEnvelope();
env.Context.Addressing.Action = e.Context.Addressing.Action;
I hope this helps. Try it and let me know here if it works.
Monday, November 22, 2004
With regards to one of the craziest brawl melee in NBA history...
Now...what are the odds of them being in Singapore in November 2004
I sent this puzzle out to a few friends who have always thought they are very smart
to see how they measure up. So far, only 2 of 12 have proven that they are not wasting time...
Making sense of the new Event-Based Asynchronous Programming Model in ASMX .NET v2.0
Http.sys is a kernel-mode networking component of Windows and is baked into the base OS of Windows Server 2003 and now, Windows XP SP2. See here for more information.
According to Don Box here, the thinking is that it's better to have one hardened implementation in the base OS than 4-5 one-off implementations in different products/technologies. Old-timers may recall that early builds of the .NET Framework installed HTTP.SYS in order to get .NET Remoting to work with HTTP (I think it was called the COM+ web server). The fact that we had to ship a one-off HTTP server implementation in .NET Remoting was an unfortunate byproduct of HTTP.SYS not having a ship vehicle that was close to .NET V1. Hopefully making HTTP.SYS part of the base OS will keep others from going down the same path.
VS2005 now comes with a Managed Framework for Http.sys (HttpListener). Even though it was possible to host ASPX and ASMX in any managed process (WinForms, ConsoleApps, WindowsServices...) since .NET v1.0, the HttpListener class that comes with VS2005 makes it a lot easier.
ASP.NET Cassini Web Server is an example of a Windows Application hosting ASP.NET and is used throughout ASP.NET v2.0. It can run on your desktop without the use of IIS.
I will show some very simplistic examples of the how-tos in hosting HTTP Processes in a Console Application using a Console Application in .NET 2.0. In this case, I have built a simple IIS-less Web Server that can churn out Web Pages, SOAP and even SOAP that is WS-* Compliant using Web Services Enhancements (WSE) 2.0 !!!
You can find information related to the above from my previous blog post here. Do take note that the codes show there are for test and demo purposes only. There needs to be major re-work and re-factoring before it can even be considered usable.
On another node, Aaron Skonnard has just published an article here that gives a detailed explanation on the above. Do check it out.
Sunday, November 21, 2004
...or is W3C
the goat here ?
Technopoly : The Surrender of Culture to Technology.
Are we losing more than that ?
Saturday, November 20, 2004
I came across some questions pertaining to how the asymmetric keys of X.509 PKI Digital Certificates
are being transmiited during SOAP Message exchanges for both XML-Encryption and XML-Digital Signature.
There seems to be some sort of slight confusion here so I will explain in a more user-friendly fashion here.
Please take note that X.509 Digital Certs generated this way are for testing and development purposes only.
Wednesday, November 17, 2004
Tuesday, November 16, 2004
The only blog that has brought tears to my eyes and a reminder to us all
Monday, November 15, 2004
I have been in a Christmasy Holiday mood for the last few weeks and have basically been in a state of lethargy.
Saturday, November 13, 2004
- Individual data objects as endpoints ?
- Resources (data objects) are like children. They need to have names if they are to participate in society - Fundamental Flaw of UDDI ?
- Any business problem can be thought of as a data resource manipulation problem and HTTP is a data resource manipulation protocol ?
While I have been looking through to see there are any interesting materials and resources using Respresentational State Transfer (REST) to implement WEB Services in .NET (since this is WEB in every sense of the word, unlike my special inkling to call it XML Services most of the time), I came across this pretty interesting resource here.
Friday, November 12, 2004
In eBay's continuing effort in support of SOAP, they will be releasing additional SOAP API calls later this month.
I had a lunch discussion with a friend some time back who argued that eBay is very heavily favoured towards Respresentational State Transfer (REST). hmm...I wonder if he knows about this.
Thursday, November 11, 2004
One of the key benefits of Service-Orientation is that it achieves reusability of business processes across layers, applications, organizations and trust boundaries.
Thursday, November 04, 2004
I could not use the newer features of the FreeTextBox since I upgraded to this dasBlog version 1.6.4121.2.
Newer features that didnt work (for me) in this FreeTextBox version include those that requires a Web Dialog Popup, namely:
- Insert VB.NET, C#, J#, T-SQL Code
- Font-Fore Color
- Font-Back Color
Thanks to Kenneth Solberg who helped me out. We managed to devise some kind of hack around it. Without knowing the full cause of this bug, I would not call this a solution. It is a hack, at best.
The hack includes these steps:
- Save a copy of the web.config file from the dasBlog root to the ftb directory
- Open up that web.config file from the ftb directory
- Edit the Authorization Config section to such: <authorization><allow users="*" /></authorization>
- Remove the Authentication Elements from the config file
- Save that web.config File back to the ftb directory
- Save a copy of the SiteConfig Folder and Contents from the dasBlog root to the ftb directory as well
- Refresh and Click on the Font-Fore Color, Font-Back Color and Insert Code Buttons of the FreeTextBox and watch the wonderful Web Dialog pop up successfully.
Since there are many questions around regarding this, I have updated and answered a question with regards to this on the temporary dasBlog Wiki site here.
Hope that at least helps someone.
With reference to my previous posted here on Real World UsernameToken Authentication Scenarios with WSE 2.0
I have received some very good responses and feedback based on that and the questions tend to continue:
Some of the feedback I have received asked about the Encryption of the UsernameToken in the ResponseStream in the example given above. Here is a sample question:
Encrypting the username token using the public key of the server ensures
that the password is encrypted in the request to the server. What happens
when the response from the server is sent to the client ? I have looked at the
the trace the output tace at the client has no password in clear text. But
the input trace on the client has a clear text password. Why ?
The username credentials returned will follow that of the request method. So, if you send a SendPlainText mode of the PasswordOption in a request [even though you encrypt the UsernameToken afterwards], the UsernameToken in the response will be sent back in PlainText as well. This happens, of course, if you added the mutable UsernameToken back into the response stream
'Add Mutable Token into the Token Collection of the Response
We cannot re-do the process we did earlier in the RequestStream by encrypting the UsernameToken again. If you remember, that was done because we had to do some Hash-Digest comparision with the Hash value stored in the user db against the Hash value generated from the Password sent in the RequestStream. Thus, the Password send have to be in PlainText mode. However, we will encrypt the UsernameToken so that it doesnt get seen on the wire. We encrypt it with the Recipient's PublicKey for the Recipient's perusal. At least, an encrypted token CAN be decrypted, a Hashed one CANNOT.
However, we cannot do the same in the reverse ResponseStream. This is because we cannot encrypt the Recipient's SecurityToken with the Recipient's key. The Recipient machine would not know how to decrypt it.
ResponseSoapContext.Security.Elements.Add(New EncryptedData(eTok, "#" & eTok.Id))
doesnt make any sense and would be invalid and the Recipient would respond with a SOAP Client error:
ApplicationException: WSE507: The order of security elements and security tokens
will cause a processing failure on the receiving end, and they must be reordered
to create a valid message.
To hack around this constraint in WSE 2.0, the best alternative I could think of and tried is to intercept the process and force the UsernameToken to be sent back with a SendHashed or better, with a SendNone Option. This can be done by typeCasting the SecurityToken that is retrieved from the earlier RequestStream to that of a UsernameToken. Then retrieve all the necessary credentials of the casted UsernameToken (eg. Username, Password) and send that details into a new instantiated UsernameToken. Then, add this newly created mutable UsernameToken into the ResponseSoapContext Stream.
'Retrieve the Signing Token from the Request Message
Dim eTok As SecurityToken = GetBodySigningToken(RequestStream)
'Retrieve the Encrypting X509Security Token from the Request Message
Dim sTok As X509SecurityToken = GetBodyEncryptingToken(RequestStream)
'CAST the SecurityToken into a UsernameToken type
eTok = CType(eTok, UsernameToken)
'Force the process to send back a Hashed or NO Password
Dim ut As UsernameToken = New UsernameToken _CType(eTok, UsernameToken).Username, CType(eTok, UsernameToken).Password, PasswordOption.SendHashed)
'Retrieve the same Cert from the Local Machine store and Check if it supports Digital Signing
Dim sX509KeyID As String = Convert.ToBase64String(sTok.Certificate.GetKeyIdentifier)
sTok = Helpers.GetSigningX509Cert(sX509KeyID)
'Add Mutable Token into the Token Collection of the Response
'Add the Message Signature into the message
'Add the Encrypted data into the message
From the ResponseStream generated, you will be able to look at the UsernameToken sent back now to the Recipient. However, the Password will be Hashed or there may be NO Password at all (if you configured to be sent back with a PasswordNone Option). Below is the trace snippet sent back from the Server to the Recipient.
Of course, if the Service Consumer has their X.509 Digital Certs as well, we can always embed a binarySecurityToken representation of the client's Public Key into the SOAP Request stream and then, in the Service Response Stream, encrypt the Consumer's UsernameToken with his own Public Key taken from the binarySecurityToken representation and dispatches it. However, this is not an elegant solution as
- Most Service Consumers do not have their own X.509 Digital Certs and therefore, we have to cater for those who dont. This means extra processing power and code is needed to parse the SOAP Message to check for the binarySecurityToken and extra logic is required to hash it back using the above method if the binarySecurityToken is not found.
- Message Payload will increase with any type of encryption as compared to hash digest and with the attachment of the binarySecurityToken as well.
Do let me know if this works for any of you or, if you have better suggestions.
It sure is great to see many people beginning to experiment and use Web Services Enhancements (WSE) 2.0. Many people I speak to and come across today are still trying to grasp the security features of WSE.
I had blogged about this earlier in my old weblog host here. However, I will just summed it up for interested parties in this post.
...While the Documentation of WSE 2.0 teaches on how to authenticate a usernameToken from a client request against a database query [I print it here for your benefit]:
Protected Overrides Function AuthenticateToken(userName As UsernameToken) As String
'BLAH BLAH BLAH
'You are supposed to be reading from a returned Database query based on the UsernameToken.userName property.
'Then you are supposed to return the Password that is returned from the DB Query here
However, it doesnt touch on one of the best practices of Security of storing passwords into a database which is to hash userpasswords and then store it in the DB. So the question is how do we compare then ?
Bearing in mind the constraints of
- Passwords must be sent from the client in PlainText Form so the service can hash it and compare against the database
- Passwords cannot be sent in Hash Digest form as the service would have NO idea on how to re-engineer the actual password from the Hash Digest
I suggest a couple of alternatives to solve this problem....Most of what you choose will depend on very much how much control you have over the client
- SSL it [The ugliest, expensive and least scalable way...but requires the least coding work]
- Send the username, password in ClearText Via the usernameToken. However, encrypt this entire usernameToken before sending it over. The pipelines of WSE will handle the decryption for you. Once it reaches your service application, you will know what the ClearText password is. Hash it and then do a straight comparison of the Hash Digest against the one returned from the Database. This method assumes that the server has the Private Key portion of an asymmetric token such as a X509 Digital Certificate or even the service has a X509 Digital Certificate to begin with and it also assumes the knowledge of the Hash Algorithm method employed by the user DB.
While the documentation may be poor, the extensibility of the UsernameTokenManager is great ! I will reproduce snippets of option  for your benefit
Dim a As localhost.IndexWse = New localhost.IndexWse
'Send PlainText Password across so that the Service can hash Digest
'this value for comparison later
Dim ut As UsernameToken = New UsernameToken _
("TestAccount", "TestPassword", PasswordOption.SendPlainText)
'Include the usernameToken in the message so the Server can verify that
'this usernameToken actually came from you
'Blah - Find the Service Public Key of its X509 Cert so only the Service
'can decrypt and read this Token
Dim store As X509CertificateStore = _
Dim cert As X509Certificate = store.FindCertificateByKeyIdentifier _
Dim tok As X509SecurityToken = New X509SecurityToken(cert)
'Sign and Encrypt everything in the message. Beware of the Payload !
a.RequestSoapContext.Security.Elements.Add(New EncryptedData(tok, "#" & ut.Id))
Public Class CustomUsernameTokenManager
Protected Overrides Function AuthenticateToken(ByVal token As UsernameToken) As String
Dim pw As String = token.Password
'Employ the same Hash function on the password that you deployed saving the passwords
'into the User DB
Dim hpw as string = userDBHash(pw)
'Compare the hpw result with the one returned from the oledbReader from the Database
'with the username as the Reference
'If it matches, return the same password from the Token
Return "A Password that is impossible to GUESS"
End Function 'AuthenticateToken
End Class 'CustomUsernameTokenManager
If you check your diagnostics and the SOAP Message Tracing Files, you will notice that the entire usernameToken is encrypted and nothing is sent over in ClearText even tho the passwordOption is set to SendPlainText.
While a lot of people have been caught up with the recent advancements of Web Services Standards of WS-I, OASIS, W3C (the advanced communication standard protocols, the framework, etc), that is just the tip of the Web Services iceberg.
Once (not if) XML Web Services becomes the de-facto standards for cross domain communication for enterprise mission-critical connected distributed systems (EMCCDS) in the future, the focus will be on the IT Infrastructure. Why ? Well, someone or something has to keep it up and make sure it stays running ;) Messages of Service-Orientation are supposed to be self-contained and independent so the BUS must be there to make sure the dispatch doesnt fail.
Infrastructure-level Web services are XML services that implement part of the distributed computing infrastructure. They support other Web services communicate with each other. In particular, these robust services (and not necessarily WEB Services in any way) are the ones that makes or breaks the communication framework. They provide such functionality as:
- Performance Managment (Message Payload, Response Time, etc)
- Operational Management
- Usage Metering
- Billing and Payments
- Routing (XML-Aware HW Appliances such as Routers and Firewalls, SW Routers)
- Orchestration (Workflows, Business Processes, etc)
- Advertisement and Discovery (WS-Discovery is key)
- Caching (Implementing different techniques and patterns for Caching, etc)
- Queuing (For added Reliability)
- State Management and Persistence (Transactional, 2-Phase Committ, Co-ordination, etc)
To understand this a bit further, now with more of a federated approach to services, there will be more applications and servers to enable the use of Identity Management, Authorization, Directory and other shared services. What follows next are supporting services and application hookups. Supporting services are especially important in crowded IT environments. “Retrofitting” has to be considered to improve extensibility (afterall, much money has been sunk in to create standards-based interfaces to reusable code). This puts further weight on the current infrastructure. Connectivity is very vital here as monolithic solutions are being cleaved apart to form intelligent shared services, then cleaved together again via connections to form a logical virtual composite system.
Very importantly, all these are very much tied to Service Level Agreements (SLAs) and Quality of Service (QoS) which will form the basis of the business returns and implications of Web Services in Service-Orientation.
Anne Thomas Manes, one the leading thought thinkers on Web Services, has an article that talks about Infrastructure Level Web Services here.
I am presently head-down and knee-deep working on writing a white paper that explains how XML Services and Service-Orientation will eventually empower the IT Infrastructure and some of the design considerations as we move forward to greater adoption of messaging-based solutions in the EMCCDS.
Monday, November 01, 2004
Posted from BLInk !
Or is the Backlash really against Offshoring ?