Monday, June 6, 2011

Microsoft; Interoperability Between Microsoft.NET WCF 4.0 and Oracle WebLogic Server 11g Using Secure Web Service, Part 2

Learn how to create secure Web services that support interoperability across Oracle and Microsoft technologies.


In Part 1, I covered the scenario where we have a service running in Oracle WebLogic Server 11g and a client consuming this service using Microsoft WCF 4.0 technology. In this second part of the series, I will cover the scenario where we have a service running in Microsoft WCF 4.0 platform and this service will be consumed using a service agent developed using Oracle ADF technology and running in Oracle WebLogic Server.

Security is a fundamental requirement in enterprise solutions to guarantee the successful adoption of Service Oriented Architecture (SOA). Key actors in the industry and standard bodies have extended the SOAP protocol to produce a series of security specifications, known as WS-* protocols, to provide end-to-end security to Web services such as message confidentiality and integrity, token exchange (SAML, Username/Password, Kerberos and X.509), trust and federation.

One recurring challenge in the integration of heterogeneous applications using Web services is the interoperability because software vendors interpret the WS specifications in order to adapt them to their platforms -- and sometimes this leads to several problems. The solution approach is the use of rules and best practices to implement interoperable Web services such as WS-I profiles.

A common interoperability scenario found in many organizations is to have an enterprise application running in Microsoft.NET platform and exposing the application functionalities using Web services approach (supporting the WS-* protocol stack) as well as a client running in an Oracle WebLogic Server environment and consuming these features in a secure way. In this article, I’m going to talk about supporting the previous scenario using emerging technologies of Oracle and Microsoft, specifically using Oracle WebLogic Server 11g and Microsoft Windows Communication Foundation 4.0.

Microsoft Windows Communication Foundation (WCF) is the infrastructure to implement distributed solutions in the Microsoft.NET world. In this programming model, the WS-* protocol stack is abstracted as a bunch of artifacts known as protocol channels. The protocol channels execute right before and after sending and receiving messages using the specific transport protocol channel. Oracle WebLogic Server 11g is the most complete application server to develop, deploy and host J2EE solutions, particularly Web services using the JAX-WS standards.

By using WCF and WebLogic Server technologies we can support several security scenarios in the enterprise environment. Among those scenarios, there is the message exchange in a distributed system using a Public Key Infrastructure (PKI) to provide a secure channel between the underlying sub-systems.

In order to support the business case, the solution must support message-level security by using WS-Security related protocols which provide the foundations for the authentication, message protection and integrity as well as a high level of interoperability. This article will focus on how to define the WS-Security configuration (using X.509 certificates as the security mechanism) for a Web service hosted in WCF 4.0 environment that can interoperate with a client running in the Oracle WebLogic Server 11g environment.

Developing the Server-side of the Solution

In order to keep things simple and to focus in the integration solution using secure Web services standards, our service will be very straightforward just doing elemental arithmetical operations such as add and substract. In a real-world Web service solution, the service implementation will be more complex consisting of invocations to the business objects that are exposing their functionalities to the outside world.
Let’s start with the development by opening the Visual Studio.NET 2010 IDE and creating a new application and the underlying solution. Enter the application and solution name and the working directory and finally click OK.


oracle-msft-interoperate-part2-f1

Next step is to add the Web service contract defining the operations of the service endpoint and data schema for the incoming and outgoing messages. In WCF 4.0, we implement the contract by using the interface syntax in C# (declaring the service endpoint’s intention without specifying the actual behavior) and annotating the interface with ServiceContact and OperationContract attributes as shown below. Notice that we have overridden the default service namespace (http://tempuri.org) because this construct is designed to uniquely identify your service and eliminate ambiguity as several services are combined.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;

namespace MathServiceConsAppl
{
    [ServiceContract(Namespace="http://www.mathservices.com/services/2010/12")]
    public interface IMathService
    {
        [OperationContract]
        int Add(int param1, int param2);

        [OperationContract]
        int Substract(int param1, int param2);
    }
}

Next step is to add the Class artifact to the project to support the service endpoint. Please, remember that we’re going to implement the behavior directly in the service endpoint but it’s not a best practice because the endpoint is basically the access point to our business logic, which is in fact implemented in business objects in our application or business logic layer:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;

namespace MathServiceConsAppl
{
    public class MathServiceImpl : IMathService
    {
        public int Add(int param1, int param2)
        {
            return param1 + param2;
        }

        public int Substract(int param1, int param2)
        {
            return param1 - param2;
        }
    }
}

Now, let’s add the main point of execution to define the hosting environment (through an instance of the ServiceHost class passing a reference to the service endpoint class) which is responsible for management of the lifetime and context of the running services. In real-world solution, the hosting environment is a process in Internet Information Services (IIS), Windows Services, and Windows Process Activation Services (WAS) infrastructures; although for simplicity we’re going to host the Web service in a console application.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;

namespace MathServiceConsAppl
{
    class Program
    {
        static void Main(string[] args)
        {
            using (ServiceHost host = new ServiceHost
                    (typeof(MathServiceConsAppl.MathServiceImpl)))
            {
                try
                {
                    host.Open();
                    System.Console.WriteLine("Press any key to finish ...");
                    System.Console.ReadKey();
                }
                catch (Exception ex)
                {
                    System.Console.WriteLine("Exception: "+ex.Message);
                }
                finally
                {
                    host.Close();
                }
            }
        }
    }
}

In order to support the message-based security using WS-Security related standards in an interoperable way, we need to configure the infrastructure using X.509 certificates. For this article, we’re going to use test certificates using the makecert.exe command. The –pe switch makes the private key exportable. The –n switch defines the common name of the certificate matching the service host’s domain (or machine) name and it’s used for the authentication. The –sv switch defines the private key file. The –sky switch can exchange or digital signature.

oracle-msft-interoperate-part2-f2

Then, we need to combine the private and public keys into a single file. The .cer file contains the public key, the .pvk contains the private key and the .pfx file is the exchange file that contains both keys. Keep in mind that certificates generated in this way should not be used in production environment, so you should request a certificate to a trusted third-party certificate authority.


oracle-msft-interoperate-part2-f3

Now, we need to import the localhost.pfx into the LocalMachine/Personal certificate store in the hosting machine. This enables the server to decrypt messages that have been encrypted with its public key and to encrypt the messages with its private key.

oracle-msft-interoperate-part2-f4

The next step is to add configuration file (app.config file) into the project with the necessary information to start the Web service using a secure mechanism:
1   <?xml version="1.0" encoding="utf-8" ?>
2   <configuration>
3     <system.serviceModel>
4           <behaviors>
5               <serviceBehaviors>
6                   <behavior name="MathServiceConsAppl.MathServiceImplBehavior">
7                       <serviceMetadata httpGetEnabled="true" />
8                      <serviceDebug includeExceptionDetailInFaults="false" />
9                        <serviceCredentials>
10                         <clientCertificate>
11                           <authentication certificateValidationMode="PeerOrChainTrust"/>
12                         </clientCertificate>
13                         <serviceCertificate
14                           findValue="localhost"
15                          storeLocation="LocalMachine"
16                           storeName="My"
17                           x509FindType="FindBySubjectName"/>
18                    </serviceCredentials>
19                   </behavior>
20               </serviceBehaviors>
21           </behaviors>
22           <bindings>
23             <customBinding>
24               <binding name="MathServiceConsAppl.MathServiceImplBinding">
25                 <security defaultAlgorithmSuite="Basic128"
26                           authenticationMode="UserNameForCertificate"
27                           requireDerivedKeys="false" securityHeaderLayout="Lax"
28                           includeTimestamp="true"
29                           keyEntropyMode="CombinedEntropy"
30                           messageProtectionOrder="SignBeforeEncrypt"
31                           messageSecurityVersion="WSSecurity11WSTrustFebruary2005WSSecureConversation
32                                    February2005WSSecurityPolicy11BasicSecurityProfile10"
33                           requireSignatureConfirmation="true">
34                   <localClientSettings
35                         cacheCookies="true"
36                         detectReplays="false"
37                         replayCacheSize="900000"
38                         maxClockSkew="00:05:00"
39                         replayWindow="00:05:00"
40                         sessionKeyRenewalInterval="10:00:00"
41                         sessionKeyRolloverInterval="00:05:00"
42                         reconnectTransportOnFailure="true"
43                         timestampValidityDuration="00:05:00"
44                         cookieRenewalThresholdPercentage="60" />
45                   <localServiceSettings
46                         detectReplays="true"
47                         issuedCookieLifetime="10:00:00"
48                         maxStatefulNegotiations="128"
49                         replayCacheSize="900000"
50                         maxClockSkew="00:05:00"
51                         negotiationTimeout="00:01:00"
52                         replayWindow="00:05:00"
53                         inactivityTimeout="00:02:00"
54                         sessionKeyRenewalInterval="15:00:00"
55                         sessionKeyRolloverInterval="00:05:00"
56                         reconnectTransportOnFailure="true"
57                         maxPendingSessions="128"
58                         maxCachedCookies="1000"
59                         timestampValidityDuration="00:05:00" />
60                   <secureConversationBootstrap />
61                 </security>
62                 <textMessageEncoding
63                     maxReadPoolSize="64"
64                     maxWritePoolSize="16"
65                     messageVersion="Soap12"
66                     writeEncoding="utf-8">
67                   <readerQuotas
68                       maxDepth="32"
69                       maxStringContentLength="8192"
70                       maxArrayLength="16384"
71                       maxBytesPerRead="4096"
72                       maxNameTableCharCount="16384" />
73                 </textMessageEncoding>
74                 <httpTransport
75                     manualAddressing="false"
76                     maxBufferPoolSize="524288"
77                     maxReceivedMessageSize="65536"
78                     allowCookies="false"
79                     authenticationScheme="Anonymous"
80                     bypassProxyOnLocal="false"
81                     hostNameComparisonMode="StrongWildcard"
82                     keepAliveEnabled="true"
83                     maxBufferSize="65536"
84                     proxyAuthenticationScheme="Anonymous"
85                     realm=""
86                     transferMode="Buffered"
87                     unsafeConnectionNtlmAuthentication="false"
88                     useDefaultWebProxy="true" />
89               </binding>
90             </customBinding>
91           </bindings>
92   <services>
93               <service behaviorConfiguration="MathServiceConsAppl.MathServiceImplBehavior" 
94                  name="MathServiceConsAppl.MathServiceImpl">
95                   <endpoint address="" binding="customBinding" bindingConfiguration=
96                      "MathServiceConsAppl.MathServiceImplBinding" contract="MathServiceConsAppl.IMathService">
97                       <identity>
98                           <dns value="localhost" />
99                       </identity>
100                   </endpoint>
101                  <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
102                   <host>
103                       <baseAddresses>
104                           <add baseAddress="http://localhost:8080/MathService" />
105                      </baseAddresses>
106                   </host>
107               </service>
108           </services>
109       </system.serviceModel>
110   </configuration>

The first element to configure is the service endpoints: in our case, one for our math service and the other for accessing to the service meta-data (lines 93-107). An endpoint contains three essential elements: the address where the service is listening, the contract defining what functionality the service is providing, and the binding defining how to communicate with the service. An endpoint may contain an optional element named behavior to set up some environment configurations. One important thing to notice in the service endpoint is the identity element to indicate the WCF platform to expect the canonical name for the service certificate to match the service host’s domain or machine name. Another important aspect is the host element to set a base address for all the services.

The binding (through the binding and bindingConfiguration attributes of the endpoint element) is tailored to support the main requirements of WS-Security and interoperability with Oracle WebLogic Server according to the product documentation (lines 22-91).
And finally, the behavior (through the behavior and behaviorConfiguration attributes of the endpoint element) tells how to locate the X.509 certificate (lines 4-21).

Developing the Client-side of the Solution

In order to create the client-side solution, let’s open the Oracle JDeveloper 11g IDE and create a new application.
oracle-msft-interoperate-part2-f5

Click on OK button. Enter the application name, default package and the working directory.


oracle-msft-interoperate-part2-f6

Click on the Next button and the Name your project page enables creating a project (in JDeveloper, an application comprises several projects) for our service client. You have to enter a descriptive name and a working directory for the project as well as to select the main technologies for the client development.


oracle-msft-interoperate-part2-f7

Click on the Next button, and we go to the Create Java Settings page to check the project structure. And finally, let’s click on the Finish button.


oracle-msft-interoperate-part2-f8

Next step in the solution is to create a JAX-WS service client. The JAX-WS specification is programming model, which allows you to implement and consume Web services by using POJO classes and Java annotations to decorate the behavior of underlying POJO classes.

The first step to create a JAX-WS service client is to add a Web Service Data Control by selecting the File | New option and click on the OK button. The Web Service Data Control in Oracle ADF 11g provides an easy and convenient programming model to incorporate web services in an ADF application. The data control abstracts the communication with a Web service thus providing a consistent mechanism for the ADF pages to access the data.

oracle-msft-interoperate-part2-f9

Click on the OK button and open the Create Web Service Data Control wizard. In the first page, enter a name for the artifact and the URL to the WSDL, which describes the service metadata.



oracle-msft-interoperate-part2-f10

Click on the Next button, and the Data Control Operations page enables to select the functionality we want to consume from the Web service. In our case, we’re going to consume all the operations in the available service endpoint.


oracle-msft-interoperate-part2-f11

Click on the Next button, and in the Response Format page we can specify the format for the message exchange.


oracle-msft-interoperate-part2-f12

Click on the Finish button to finish the creation of the Web service data control. Next step is to configure the data control, so right-click on the control and select the Define Web Service Security option from the context menu.


oracle-msft-interoperate-part2-f13

When the Edit Data Control Policies windows appear, we need to select oracle/wss11_username_token_with_message_protection_client_policy policy to allow the client to propagate a fixed identity to the web service at the same time providing security to the entire SOAP message. This is the policy (according to the WebLogic documentation) that enables interoperability with WCF 4.0 solutions.

oracle-msft-interoperate-part2-f14

This policy enforces message-level protection and authentication for inbound SOAP requests in accordance with the WS-Security 1.1 standard. Messages are protected using WS-Security's Basic 128 suite of symmetric key technologies, specifically RSA key mechanisms for message confidentiality, SHA-1 hashing algorithm for message integrity, and AES-128 bit encryption. Credentials are provided through the UsernameToken WS-Security SOAP header. Plain text as well as digest mechanisms are supported. The default configuration is in the jps-config.xml file under the directory WL_DOMAIN/config/fmwconfig, where WL_DOMAIN variable is the directory of the WebLogic Server’s domain. The default credential store points to the cwallet.sso file and the default keystore points to the default-keystore.jks.

Then click on the Override Properties button in order to provide configurations for the csf-key and keystore.recipient.alias elements.


oracle-msft-interoperate-part2-f15

The csf-key property defined the key in the credential store that holds the user to be propagated to the web service in the UsernameToken header. This is used to authenticate to the Web service without actually embedding the username and password into the policy.

In order to create it at runtime, we need to execute the following WLST command in the client WLS domain as shown below. WLST command from the EM interface is located in the MW_HOME/oracle_common/common/bin where the MW_HOME variable is the Oracle middleware directory. In order to use the WLST command, we need to connect to a WebLogic Server domain.
createCred(map="oracle.wsm.security",key="mathclient-key",user="username",password="password")

In order to create it at development time, we need to click the New Key button to define the key and to push this configuration into the WLS domain credential store when you deploy your application.


oracle-msft-interoperate-part2-f16

The keystore.recipient.alias property is the reference to the alias name for the server-side X.509 certificate in the WLS client domain’s keystore. In order to import the server-side X.509 certificate as a trusted certificate in the keystore, you should execute the keytool command:

keytool –import –trustcacerts –alias localhost –file localhost.cer –keystore default-keystore.jks

In order to enable the application server to access to the default-keystore.jks keystore, execute the following WLST command in the client WLS domain.

createCred(map="oracle.wsm.security",key="keystore-csf-key", user="keystore", password="weblogic1")

The next step is to configure the user interface to interact with Web service.Let’s open the faces-config.xml file to configure the pages and the underlying page flows. Drag and drop a JSF page from the JSF Diagram Objects onto the faces-config designer.

oracle-msft-interoperate-part2-f17

Finally, double-click on the index.jsp page to create the page and drag and drop the operations from the DataControl menu.

oracle-msft-interoperate-part2-f18

Now we’re ready to start testing the application in a real scenario.


oracle-msft-interoperate-part2-f19

Now that you have read this article explaining how to create secure Web services using WS-* standards and Microsoft technologies, as well as to consume the Web service using Oracle technologies, you can adapt this sample use case to your own business scenario to build robust enterprise-wide solutions using this approach.

No comments :

Post a Comment