Chapter 3. Extending SOAP for security

This chapter covers

  • Extending SOAP with Headers
  • WS-Security with JAX-RPC handlers
  • SOAP intermediaries and WS-Addressing

Chapters 1 and 2 provided the background needed to start exploring SOA security. In chapter 1, you learned the basics of SOA and how it impacts security by lowering the barriers between applications. In chapter 2, you reviewed the basics of the most popular approach to realizing SOA—creating and consuming SOAP-based web services. What you have not seen yet is how SOAP can address the security concerns expressed in chapter 1.

SOAP does not address any security issues directly. In fact, it does not directly address other common requirements such as reliability or transactionality, either. SOAP simply provides a mechanism by which it can be extended to address additional concerns such as security, reliability, and transactionality. Is this a good idea? Shouldn’t something as fundamental as security be addressed in the base SOAP specification itself? We’ll answer this question first up in this chapter. Once we do that, we will describe the header-based extension mechanism SOAP provides and introduce WS-Security, a standard extension for security in SOAP.

How do SOAP-processing engines (such as Apache Axis, introduced in the previous chapter) allow for the processing of extensions such as WS-Security? This is an important question that must have popped into your mind once we mentioned that concerns such as security are addressed by SOAP extensions and not by SOAP itself. We will answer this question as well in this chapter, and show you the handler pattern supported by most SOAP engines to process SOAP extensions. Specifically, by continuing the example of a brokerage service introduced in chapter 2, we will show how to process SOAP extensions using Apache Axis.

Toward the end of the chapter, we will briefly introduce the idea of intermediaries. Intermediaries are nodes that are neither the source nor the destination endpoints for a SOAP message. They come in handy when it is desirable (for manageability and other reasons) to separate handling of extensions such as WS-Security from endpoints. For example, a centralized security service may be implemented as an intermediary that intercepts all SOAP traffic and enforces security policies.[1] We will also introduce WS-Addressing, a standard that is useful when routing messages across intermediaries. We will conclude the chapter by answering some of the frequently asked questions about the usage of SOAP extensions, headers, and handlers.

1Chapter 8 will elaborate on this idea in great detail.

We start with a discussion on what is the right approach for addressing security in SOAP.

3.1. Finding the right approach for security in SOAP

As SOAP-based web services are the most commonly found services in today’s SOA implementations, can we add a security specification into SOAP itself? For good reasons, the designers of SOAP chose options other than building the security protocols into the SOAP standards. In this section, we will learn about those reasons and the choices made by designers of SOAP.

Before looking at the choices the designers faced, we will briefly discuss security in web applications. This discussion will later make it easy for you to see the reasoning behind the choices made in SOAP.

3.1.1. Lessons from web authentication schemes

A web application has multiple layers where security can be implemented (figure 3.1). For simplicity, let us focus only on authentication and how it can be implemented in each of these layers.

Figure 3.1. Authentication in web applications can happen at three different layers. At the transport layer, SSL certificates can be used for authentication. At the HTTP layer, the basic or digest schemes that can be implemented by the browser can be used for authentication. At the application layer, the choices are endless—we can use form-based authentication, with full control over client-side and server-side for the programmer.

There are three layers where we can implement authentication in web applications:

  • Transport layer
  • HTTP layer
  • Application layer

Authentication in each of these three layers has advantages and drawbacks.

Authentication at the transport layer

First, we can use the information available at the transport layer. For instance, we can allow all requests coming from specific IP addresses. Or, we can restrict access to users with a verifiable SSL certificate.[2] Technically, this kind of security can be provided without the web server knowing about it. In practice, these facilities may be integrated into the web server, for ease of use.

2Chapter 6 will introduce SSL and certificates in depth

IP address-based authentication is not good enough in most real-world web applications. Web applications generally must be accessible from everywhere. Furthermore, the threat of an attacker spoofing the IP address[3] makes IP address-based authentication ineffective for real-world use.

3 Yes, an attacker can indeed fabricate/manipulate IP packets in such a way that the server receiving the packets thinks that the sender (the attacker in this case) is at a different IP address than where he really is.

Authentication based on client SSL certificates is a technically superior approach to most other authentication schemes. However, it is difficult to enforce in practice, as not all end users of a web application may be equipped with an SSL certificate.

3.1.2. Authentication at the HTTP layer

At the HTTP layer, the web server can ask the client for username and password information. Almost all web servers can be configured to carry out what is known as HTTP Basic Authentication. In this scheme, the web server returns a 403 Authorization Required response to a client whenever it receives a request that does not have a username and password embedded as a header. The client (a browser, for example) is then supposed to prompt the user for username and password and resend the request with the typed-in credentials embedded as an additional HTTP header. HTTP can provide another—in fact, stronger—security mechanism called Digest Authentication, which is not widely implemented in browsers. Since these authentication schemes are built into the protocol, the application does not have to bear the burden of carrying out authentications.

Although it is simple for web applications to delegate the job of client authentication to the web server, this is not too widely done because it does not provide enough flexibility and control for developers. Every web server will support a few popular credential stores such as a password file or a LDAP directory. Authentication against any other credential stores will require extensions to the web server.

Authentication at the application layer

The application can use its own custom scheme instead of or in addition to transport-layer and HTTP-layer authentication schemes. For instance, when you log in to your Yahoo! account, you are challenged to enter your username and password into a HTML form. Of course, the application could also ask your age, sex, and even your mother’s maiden name. The application itself is responsible for what to ask, how to validate the answers, and how to use the results. This approach is the most general one, and is suitable in most cases. However, it is nonstandard and creates integration issues. For example, if the web application needs to be integrated into a portal, the custom authentication mechanism used by the application needs to be integrated with the portal’s authentication mechanism using one of the several proprietary Single Sign-On (SSO) solutions available in the market. Still, developers often choose to implement security at the application layer because that is what they are used to. This might be fine for web applications that are not too frequently integrated into a portal, but for web services whose very reason for existence is integration, implementing authentication and other forms of security at the application layer may not be appropriate.

We have seen three different approaches that give varying degrees of control to the developer. In particular, even though authentication at the HTTP layer is very convenient, and is a part of HTTP standard, it did not become popular. Instead, developers ended up using nonstandard, unique mechanisms using form-based authentication systems.

The lesson for SOAP-based web services is clear. Naturally, they should support a standard for security mechanisms. Yet, the standard should provide the required flexibility and control to the developers. Let us take a look at how the designers of SOAP responded to this challenge.

3.1.3. Choices for security implementation in SOAP

Just like authentication in a web application, security in SOAP can be implemented at three different layers, as identified in figure 3.2:

  • Transport layer
  • SOAP layer
  • Application layer
Figure 3.2. Three logical layers at which security in SOAP can be implemented. Unlike in figure 3.1, where the transport layer referred to TCP/SSL, the transport layer here represents higher-level protocols by which SOAP messages are exchanged. The SOAP layer refers to web services engines that can produce/consume standards-compliant SOAP messages. The application layer is free to interpret the SOAP messages, where the security can be implemented as a private standard between the producer and the consumer.

In the context of SOAP, the phrase transport layer refers to more than just TCP and SSL. It also refers to higher-level protocols such as HTTP, FTP, SMTP, and JMS/MQ that can be used to carry SOAP messages. The phrase SOAP layer refers to the engines that help expose business logic in applications as SOAP-based services. And, by application layer, we mean the end applications that constitute service providers and service consumers. Let us look at the pros and cons of implementing security at each of these three layers so that you understand the choices faced by designers.

Transport-layer security

There are protocols that let the transport layer take care of security. For example, several applications such as CVS (a popular version control system) let Secure Shell (SSH) provide a secure channel. The disadvantages of implementing security in the transport layer are twofold:

  1. Transport layer security is limited to point-to-point interactions. We discussed this in detail in chapter 1. If a message needs to travel through several applications, of which some of the applications are only allowed to look at parts of the message, we cannot use the transport-layer security mechanisms. What we need is message-level security to support the multiapplication interaction found commonly in SOA implementations.
  2. Applications cannot obtain security context easily from the transport layer. That means they cannot easily find out information such as the authenticated user’s name, role, and other details from the transport layer that authenticated and authorized the user. The problem is that there is no uniform standard to carry the security details from the transport layer to the application layer. This is because it is difficult to create a standard that is well suited for use across different kinds of transports.

The more efforts we make to provide generalized security and security context communication in the transport layers, the more we realize that it is easier to do at higher layers; that is, the SOAP layer or the application layer. Of these two, for reasons that will become obvious shortly, we will consider first the suitability of the application layer.

Application-layer security

Instead of implementing at the lower transport and SOAP layers, we could leave the security details to the application. This choice brings its own set of problems:

  1. Since each application develops its own mechanisms, integration becomes difficult. For example, when two or more low-level services are composed to create a high-level service, the custom security mechanisms in each service will have to be integrated, possibly by implementing a custom SSO solution.
  2. Getting security right is notoriously difficult. When application developers are charged with the task of developing a security framework, the odds are high that they will get it wrong.

In summary, while a suitable security model can be developed at the application level, it is costly, error-prone, and not suitable for web services.

SOAP-layer security

Now that we know that the other two choices are nonstarters, we are left with implementing security measures in the protocol itself. There are some lessons to learn from history here. If you recall, HTTP has authentication built-in, which is neither complete nor suitable for a large number of applications, requiring applications to implement their own security models. What prevents us from repeating the same mistake with SOAP? In other words, the primary challenge is to implement a universally acceptable security model in SOAP.

SOAP solves this problem by not building a security model into the SOAP protocol itself. Instead, the SOAP protocol is extensible meaning it supports security extensions. This strategy also happens to be the right choice for addressing other horizontal concerns such as reliability and transactions. In fact, there is precedent for these kinds of extensions. Let us study one such example from well-established standard protocols to see how we can draw lessons for SOAP.

In Simple Mail Transfer Protocol (SMTP), mail message headers such as From, To, and Reply-To are standardized. But what if an application wants to send a photograph of the sender as a header? The application may want the image only in a header, and not in the body, for a good reason: it may want to interoperate with other mail readers that do not understand how to process an image.

The solution is simple: SMTP allowed extension headers called “X-headers.” Any vendor can make up a header that starts with “X-.” For example, Emacs-based mail readers adopted a header named X-Face for sending the sender image. Web-based mailers adopted X-Originating-IP for recording the IP from where the mail is submitted.

SOAP provides a similar extension by headers mechanism that can be used for addressing security. In fact, SOAP’s extension mechanism is lot more powerful than what you may expect from the analogy with SMTP. SOAP explicitly allows intermediaries—parties other than a sender and intended receiver—to act on headers, and this turns out to be quite useful when addressing security needs using headers. For instance, enterprise services can use this leeway to delegate away most if not all of the burden of security enforcement to specialized security devices in the path of SOAP messages.

As you can see, there are quite a few advantages to addressing security needs at the SOAP layer using extensions. First, SOAP makes it easy by providing a powerful extension mechanism. Second, there will never be any fear of getting locked into a particular security model that may not meet the needs of every possible scenario.

There is one downside, though. If security is left to extensions, each vendor may define a different security extension, damaging interoperability severely in the process. This possibility can be avoided by creating a standard security extension. Of course, if the security needs of a particular scenario cannot be met with the standard security extension, one is always free to create one’s own security extension.

Given our conclusion that security is best addressed as an extension to SOAP, we need to first understand the details of how SOAP can be extended. We will work on that in the next section. Once we see how SOAP can be extended, we can apply our learning to start understanding WS-Security, the standard security extension for SOAP.

3.2. Extending SOAP with headers

SOAP allows for extensions in the form of headers. SOAP does not specify any headers by itself; instead, it provides a framework for incorporating and processing arbitrary headers. It specifies where headers can appear in a message, how they can be encoded, and what every SOAP engine or SOAP-based web service must adhere to when processing headers. The actual content of headers is governed by mutual consent of service providers and service consumers. For example, in an organization, the IT department can mandate certain header entries for the purpose of IT governance.

This situation can be chaotic, with each company defining its own SOAP extensions using custom headers. However, SOAP extensions for addressing common problems such as security are standardized by groups like OASIS. One such standard extension, WS-Security, defines a header related to security, and obviously, is of particular interest to us. In this book, we show how this standard extension can be used to develop security solutions for SOAP-based web services.

In this section, let us see what kind of support SOAP offers for headers. We will also introduce WS-Security.

3.2.1. Anatomy of a SOAP header

The basic structure of a SOAP message was introduced in chapter 2. As you may recall, a SOAP envelope consists of a header and a body. It is analogous to HTTP, where the body may be thought of as containing the payload—the material of interest to the application, which is typically business-level queries and results—and headers are used to negotiate application capabilities, cookies, authentication information, and other details that help the recipient make sense of the payload. The syntax, of course, varies a little bit.

Header entries

Figure 3.3 depicts the location and composition of the Header element in a SOAP envelope. The header, if present, should be the first immediate child element of the SOAP envelope. All immediate child elements of the Header element are called header entries. (It is common to refer to a header entry as header in contexts where it is clear that the term refers to a header entry and not to the entirety of a SOAP message header.) A header entry is identified by its fully qualified element name, which consists of the namespace URI and the local name. All header entries must be namespace-qualified.

Figure 3.3. Place of header and header entries in a SOAP envelope. Within the SOAP envelope, any number of headers can be introduced prior to the body element. Any organization can make up its own header, keeping the SOAP message syntactically valid. Most useful headers are ones where there is wide industry support and tool support.

Let us consider an example. Say we want to add a header entry to carry the name of the company sending the message. Listing 3.1 shows how to use a header entry to indicate that Manning Publications is the message sender. To make it clear that this header is created by us, we will give it the name MyHeader:

Listing 3.1. Simple SOAP header entry example to add sender information

As you can see, we introduced a header entry called MyHeader in the namespace identified by a URI . Of course, barring the XML syntax, these headers look very similar to the ones in SMTP headers. So, how does SOAP go farther than SMTP in extensibility? We will describe this next.

3.2.2. Standard header entry attributes

SOAP defines a few standard attributes that may be present on every header entry. The semantics associated with these standard attributes are fixed by the SOAP specification; it is these semantics that make SOAP extensibility lot more powerful than that of SMTP. The standard attributes defined by SOAP for header entries answer key questions that might come up in processing of the headers:

  1. Who should deal with the header entry? Unlike in SMTP, where there is no provision for associating a target for the header data, SOAP 1.1 defines an optional actor attribute (renamed role in SOAP 1.2) to indicate who should process a header entry. How can anyone other than the recipient of a SOAP message see and process a header entry? As we very briefly pointed out in the previous section, SOAP allows intermediaries to see and process header entries. Later in this chapter, we will describe in-depth the idea of intermediaries and the significance of the actor attribute. For now, just note that it is possible to indicate who should process a header entry by providing a URI as the value for the optional actor attribute.
  2. What do we do with the header entry? The answer to this question lies entirely within the application. However, a SOAP header entry can indicate using the mustUnderstand attribute whether the application must understand the header entry. This attribute can be very effective in managing the evolution of higher-level protocols on top of SOAP. For example, it is an excellent way to introduce backward-compatible protocols.
  3. How do we parse data in the header entry? If the data within a header entry can be encoded in multiple ways, a standard attribute named encoding-Style can be used to convey the encoding used. (We covered the details of encoding in chapter 2.)

Now, we can look at a more advanced example that illustrates these three attributes on a Header element. Let us imagine that we want to add transaction information, which contains the date and time as well as the initiator of the transaction. We want to add this information for the benefit of some party that is interested in transaction metadata. We may encode it in any way we want; we will choose SOAP encoding described in chapter 2. Listing 3.2 shows how we do this.

Listing 3.2. SOAP Header element attributes

In this example, we defined a new Header element called transaction. This element takes the following attributes:

  • actor: The actor attribute describes who the transaction header entry is targeted to. We will further describe this attribute in section 3.5.2. In SOAP 1.2, this attribute is renamed role and is more generic than actor. This element specifies who is supposed to act on this entry.
  • mustUnderstand: SOAP defines a mustUnderstand attribute to indicate whether a header entry must be understood by the actor at which it is targeted. By default, it is 0, which means the header entry need not be understood by the actor. That is, the actor is allowed to ignore it. On the other hand, if is set to 1, the targeted actor must act on the header entry. If it cannot, this constitutes a fault. A specially defined MustUnderstand fault code should be used in the generated SOAP fault.[4]

    4 SOAP 1.1 strictly mandates that faults generated due to problems in headers should not use the fault detail element. In fact, the standard mentions that the absence of a detail element in a fault can be used to conclude that the fault lies in a header entry and not in the request body. SOAP 1.2 relaxes this restriction. It also introduces a NotUnderstood header entry for conveying information on a mandatory header entry that could not be processed.

  • encodingStyle: For the encoding style that is used to serialize the data in the Header element, we can use any encoding scheme that is understood by both the sender and the receiver. This understanding must be established via out-of-band communication. The details of encoding are not a part of the SOAP message.

SOAP 1.2 defines an additional standard attribute named relay. We will describe this later in this chapter when we introduce the significance of actor attribute.

Now that we understand how to extend SOAP with headers, let us turn our attention back to extending SOAP for the purpose of addressing security. From the discussion so far, it is obvious that if we want to extend SOAP for addressing security, we need to create new header entries that will carry security-related information in a SOAP message. As we saw in the previous example, anybody can extend SOAP by making up their own header entries. However, when the intent of an extension is to address a universal concern such as security, the extension needs to be standardized. This standardization will ensure interoperability and in the long run bring down the cost of using the extension, as SOAP engine vendors build in support for standard extensions. WS-Security is a good example of this process in action. It provides a standard for extending SOAP to address security concerns. The next section introduces WS-Security.

3.3. WS-Security: The standard extension for security

We saw in the previous section that SOAP can be extended by defining new header entries. While new header entries act as a vehicle for carrying additional information in a SOAP message, new header entries by themselves will not be sufficient to create a new standard. A standard should also specify how receiving parties should interpret and act on the new header entries proposed by it. In other words, a standard SOAP extension must specify the syntax as well as the semantic interpretation of new header entries. WS-Security carries out this task for addressing security in SOAP. It standardizes the names and the semantics of the entries used for security.

In this section, we will introduce WS-Security. In particular, we will describe:

  • The Security header entry proposed by WS-Security
  • How receivers should interpret and process the Security header
  • What is not covered by WS-Security
  • An example showing WS-Security in action

We will start with a discussion of the Security header entry proposed by WS-Security.

3.3.1. Introduction to WS-Security

WS-Security defines a Security header to make security claims and ensure message-level security. A security claim is any statement made regarding security. Here are some examples of security claims:

  • “My name is X.”
  • “X is authorized to access this resource.”
  • “This message is signed by X.”
  • “This message is encrypted using X’s public key.”

Of course, more than one claim can be made at the same time.

Let us start off with an example showing a simple user identity claim made using username and password.

We see here that the Security header entry is used to carry security-related information. The interesting element in this example is UsernameToken within the Security header entry. It carries an identity claim made using Username and Password elements. To keep the contents of the Username and Password elements confidential, they are encrypted.

We will see later that UsernameToken is one of the many kinds of security tokens that WS-Security uses to carry security claims. Think of a security token as simply a collection of one or more security claims. In this example, a UsernameToken is used to claim that the message is from a particular user.

How a token should look and how it should be used are defined by a WS-Security token profile. For example, the use of UsernameToken is standardized by the WS-Security UsernameToken profile. There are many other kinds of security tokens, such as X.509 certificates and Kerberos tickets. These will be discussed in chapters 4 through 8.

WS-Security defines standard security tokens that can express popular security claims. They should be sufficient for most of your needs. If you want to use your own security tokens, WS-Security allows you to do so, using custom elements and attributes within Security header entries. Of course, since these are not standard, the receiver may not understand them, unless there is a prior understanding between the sender and receiver about the semantics of these entities. If the receiver cannot understand a custom element or attribute, it has two choices: it can ignore them based on the local policy, or it can generate a fault.

Speaking of faults, WS-Security defines additional fault codes that can be used to communicate problems encountered when processing claims in the Security header entry.

WS-Security and SOAP fault codes

If a service chooses to report a fault when it finds problems with a Security header entry, it should always use the SOAP fault mechanism. The SOAP fault mechanism specifies a set of standard fault codes, and the syntax of the fault element, as you have seen in chapter 2. Table 3.1 lists the additional fault codes defined by WS-Security.

Table 3.1. Fault codes defined by WS-Security. These fault codes are to be used by any WS-Security implementation when it reports the problem with a security header entry.

Code

Description

UnsupportedSecurityToken An unsupported security token was provided.
UnsupportedAlgorithm An unsupported signature or encryption algorithm was used.
InvalidSecurity An error was discovered while processing the security header.
InvalidSecurityToken An invalid security token was provided.
FailedAuthentication The security token could not be authenticated or authorized.
FailedCheck The signature or decryption is invalid
SecurityTokenUnavailable Referenced security token could not be retrieved.
Beyond WS-Security

So far you know this: WS-Security supports security tokens that make security claims. At this point, we should point out that there are several questions that are not answered by WS-Security:

  • How does a service verify the claims made in a WS-Security header entry?
  • What keys and algorithms can be used to encrypt or sign message data?
  • If the claims in a request prove to be correct, how should the request be authorized, and by whom?
  • How does a service advertise its security policies?
  • Can a client demand a certain quality of security?

WS-Security doesn’t give any particular answers to these questions. There is a reason why: WS-Security does not prescribe a single security model. WS-Security, along with other related standards such as WS-Policy, provides the syntactic and semantic support needed to implement any security model in the context of web services.

Now that you know the basics of WS-Security, it is time we showed you a working example. Here’s what we will do:

  1. We will start with a small example that illustrates a simple security header entry. You can run this example with the code that we provided.
  2. We will subsequently describe the code used to produce such a header entry and consume a header entry using the SOAP engine that we chose in chapter 2, namely Apache Axis.
  3. We will describe the details of configuration.

The ideas illustrated by this simple example will be reused time and again in subsequent chapters. We will explain the example in great detail.

3.3.2. Example: Identifying a brokerage service user

Let us consider a small example where we will write a service that understands a WS-Security Security header entry. In this example, there are two nodes: a sender (service consumer) and a receiver (service). The sender will send the username using a UsernameToken in the Security header entry. The receiver will receive the username and use it to send a response back. To make matters simple, the receiver just has to add the username to the response. Figure 3.4 illustrates this process.

Figure 3.4. A simple request/response illustrating the use of a header entry for carrying user ID. The sender sends a user ID in the SOAP header using a WS-Security standard header. The receiver’s response is based on the user ID received from the sender.

 

Note

Of course, all these requirements can be met without using header. We can rewrite the server and client to modify the SOAP message. However, as we described earlier, there are distinct advantages in using header entries.

 

In the real world, we would not send a mere username; we would send the complete credentials, encrypted, so that the service could validate them. Here, we merely want to show how to add a header entry from the sender side and process a header entry on the receiver side.

Before we discuss the code, let’s run the example. Table 3.2 lists the steps to complete.

Table 3.2. Steps to add a header entry

Step

Action

How To

1 Set up your environment. If you have not already set up the environment required to run the examples in this book, please refer to chapter 2 to do so. ant deploy should install all the examples.
2 Restart Tomcat server. Run shutdown and startup scripts (.bat files if you are using Windows and .sh files if you are on Linux/Solaris/OS X) found in Tomcat’s bin directory.
3 If it is not already running, start TCP monitor. Run ant tcpmon. It should pop open a tcp monitor that shows all the traffic between the Tomcat server and our applications.
4 Run ant demo –Dexample.id=2. You should be able to view the request-response pairs going through the tcpmon console.

If everything goes well, you will see the screen shown in figure 3.5.

Figure 3.5. Tcpmon screenshot showing the result of adding our header entry. Observe that the request message contains a header entry with Username in it. Also observe that the orderId in the response contains the Username provided in the request.

Just as in the web service invocation example shown in chapter 2, the current example demonstrates the invocation of all the methods offered by the brokerage service. You will see that all the SOAP request messages captured by tcpmon now include a WS-Security Header element with a UsernameToken inside it. We changed the createMarketOrder and createLimitOrder implementations to include the username as part of the returned order ID. Observe in figure 3.5 that the user name, chap, sent as part of the UsernameToken in the Security header entry of the request, is returned as a part of the orderId element in the createMarketOrderResponse.

From this example, the following can be observed:

  • The sender added a standard WS-Security header entry with the user ID.
  • The receiver parsed and analyzed the header entry and picked out the username. And, it sent back the response with the username, illustrating that it indeed got the username.

There are several ways you can implement these tasks in the code. However, we want to be able to do these tasks without changing the client and service code. Since the header entries are extraneous to the actual task, if we can separate the implementation of header processing from the implementation of the actual client and service, we can better maintain the client and service implementations.

In the next section, we will introduce the concept of handlers. These handlers will help us write the code that can be configured to run on both the client and service sides to add and understand the header entries. In this case, since the server’s (i.e., the receiver) response depends on the header entry, we will show how the handler can communicate information it computes from the header entries to the actual service code. Figure 3.6 shows how it would all fit in.

Figure 3.6. Illustration of how handlers can produce and consume the header entries and communicate context to a service. The client-side handler adds the header entry and the server-side handler consumes the header entry. These handlers are actually part of the sender and receiver applications, respectively, and are implemented as libraries. Notice that the SOAP message passed between the applications contains the WS-Security Header element.

As figure 3.6 illustrates, handlers not only can produce and consume header entries; they can also communicate the results of their work to the actual service code using a context.

In the next section, we will introduce handlers and show you how to put them into action in Apache Axis.

3.4. Processing SOAP extensions using handlers

As we mentioned earlier, SOAP allows for any kind of extensions, including ones that are completely homegrown, as long as they are syntactically correct. But how can a SOAP engine possibly know how to deal with the extended SOAP message? Even if extensions are standardized, not all standard extensions can be supported by all engines. We need a generic mechanism to deal with extensions. Almost all SOAP engines out there provide a mechanism by which we can process SOAP extensions without having to modify the service itself. The mechanism is called a handler in the JAX-RPC/Axis world and a SOAPExtension in the .NET world.

In this section, we will show how handlers work. We will describe how they work in abstract, and then show the actual implementation, with annotations.

3.4.1. How handlers work

Handlers can be configured in several different ways. They can be configured on both server-side and client-side engines. Depending on the SOAP engine in use, handlers can be registered by service, by transport, or globally for all services and transports. Server-side handlers intercept requests on their way into the service and responses on their way out of the service. Client-side handlers intercept requests on their way out and responses on their way in. Figure 3.7 illustrates the sequence in which client-side and server-side handlers are invoked during request and response flows.

Figure 3.7. Sequence in which client-side and server-side handlers are invoked during request and response flows. Client-side handlers intercept requests on their way out to the service and responses on their way in. Server-side handlers intercept requests on their way into the service and responses on their way out.

What does a handler do with the intercepted message? Typically, handlers create or consume one or more SOAP Header elements in the request or response. In our example, the client-side security handler added a WS-Security element into the header. The server-side handler consumed the same header, and perhaps can use it to enforce security.

Handlers can do a lot more than merely work with headers. Some handlers may modify the message body itself. An internationalization handler may replace certain parts of the message with their equivalents in a different language. Some handlers may not change anything in the message but may simply cause a side effect. For example, an audit handler may log parts of the request and response in a database.

These handlers can be written in two different ways. We can use the APIs provided by Axis itself, or we can use the JAX-RPC handler APIs for portability reasons. To take advantage of portability, we will use JAX-RPC handler APIs in our examples.

The Java packages to understand for implementing JAX-RPC handlers are:

  • javax.xml.rpc.handler
  • javax.xml.rpc.handler.soap
  • javax.xml.soap
  • javax.xml.namespace

The first two of these packages are standardized as part of the JAX-RPC specification. The third is defined by the SAAJ specification. The last is defined by the Java API for XML Processing (JAXP) standard. You will find the javadocs for these packages in Axis documentation folders.

Now, you understand how we can use handlers to introduce and consume the header entries. We will show the actual implementation in the next section using JAX-RPC API, providing a step-by-step explanation so that you can follow the details.

3.4.2. Outline of the solution

We have two handlers in the package com.manning.samples.soasecimpl.example2:

  1. We need one handler on the sender-side (client-side). It should add the user ID to the SOAP message when it intercepts the request on its way out. ClientSideWSSecurityHandler is the class that implements this handler.
  2. We need another handler on the receiver side (server-side). It should intercept the request on its way in and parse the headers. Also, it should send the user information to the service in some fashion. In our example, we use a class named WSSecurityUsernameHandler.

Let us now look at the implementation of these two handlers in Axis. First, we need to understand the basic technical details of implementing a JAX-RPC handler, as explained in the next section. We will use the server-side handler to introduce JAX-RPC. That means the header entry is already there in the message—we will show how to extract it and communicate it to the service.

3.4.3. Implementing a server-side JAX-RPC handler

To implement a JAX-RPC handler, you need to implement the javax.xml.rpc.handler.Handler interface. Unless your handler is already extending some other superclass, a convenient alternative to implementing all the methods in the handler interface is extending the javax.xml.rpc.handler.GenericHandler abstract class. If you look at the code for the example we ran earlier, you will see that we extend GenericHandler and name it com.manning.samples.soasecimpl.example2.WSSecurityUsernameHandler.

Handler initialization

JAX-RPC requires that your handler class provides a default constructor. If you need to initialize your handler based on configuration parameters, override the init(HandlerInfo) method. The javax.xml.rpc.handler.HandlerInfo instance passed to your init implementation provides access to the configuration parameters as a name-value map.

For example, a client-side handler that adds a security-related header to the request might want to keep open the choice of actor at whom the header is targeted. Each client application that relies on the handler can then configure the parameter to target the header at the right actor.

public void init(HandlerInfo handlerInfo) {
    Map config = handlerInfo.getHandlerConfig();
    targetActorURI = (String)
      config.get(TARGET_ACTOR_PARAMETER_NAME);
}

Similarly, a server-side handler may look for configuration parameters such as locators for password stores and cryptography keys. These can be obtained the same way.

Handling requests, responses, and faults

A JAX-RPC handler can intercept requests by implementing the handleRequest method. Successful responses—responses that do not carry a SOAP fault—can be intercepted by implementing the handleResponse method. Responses that carry back SOAP faults can be intercepted by implementing the handleFault method as shown in figure 3.7.

In all cases, the handle methods should not save any message-related state within the handler. There is a reason for this restriction: the JAX-RPC runtime should be able to pool and reuse handler instances. Then, how do these handlers keep any information about the message? It is done through an instance of javax.xml.rpc.handler.MessageContext. This instance contains properties modeled as name-value pairs. Let us see how this instance can be used. When a server-side security handler authenticates the user, it may communicate that information to other handlers via user ID saved as a property in the MessageContext. Listing 3.3 is an extract from WSSecurityUsernameHandler.java demonstrating this.

Listing 3.3. Extract from com.manning.samples.soasecimpl.example2.WSSecurityUsernameHandler: Reads a username from the WS-Security header and saves it in the MessageContext

The code in this listing, despite its length, is very straightforward. We are always supplied a context to begin with as an argument to handleRequest. We get the message from the context as a first step. Next, we get the SOAP envelope from the message. Next, we get the header from the envelope and the Security element , which is a WS-Security-defined header entry, from the header. (Remember that the header can contain any number of entries. We are only interested in headers that are targeted at us; that is, those with actor/role URIs matching one of the URIs in our roleSet. We will elaborate on the concept of actor/role in section 3.5.2. We are passing “true” as the last argument to getHeaderByNameAndActor to indicate that the handler is deployed as part of an endpoint. You will have to wait until section 3.5.2 to understand the need for this information.) Next we get a username token from the header entry named wsse:UserNameToken. We get the username element from the token. Finally, after seven steps, we have the username extracted from the element.

Now that we have the user ID, we must somehow communicate it to the service. We save the username in the message context for that purpose. The receiver has access to the message context and can extract the username if it requires. Finally, the handler removes the security element in the header.

Now that the handler has set the username in the MessageContext, how does the service use it? Listing 3.4 illustrates this with an extract from Example2SoapBindingImpl.

Listing 3.4. Extract from com.manning.samples.soasecimpl.example2.Example2-SoapBindingImpl: Reads username from MessageContext and uses it as part of the business logic

The MessageContext instance associated with this service instance is available at the start of the service life cycle, through the context object passed to init. Next, it gets the username from the context . What the client does with the username depends on the business logic. In the example here, we are making use of it as a part of the ID we assign to the created order.

3.4.4. Implementing a client-side JAX-RPC handler

Now that we have seen how the server takes care of the header, we will examine how the client can insert the header into the SOAP request. The file ClientSideWSSecurityHandler.java contains the code for this handler.

The relevant part of the code is shown in listing 3.5:

Listing 3.5. Extract from com.manning.samples.soasecimpl.example2.ClientSideWSSecurityHandler: Writes username to the WS-Security header before it is sent

Just as in the server-side handler, the client-side handler gets access to the SOAP envelope through the message, which it gets from the context. Now, it will have to create the header entry and add it to the envelope. As a first step, it creates the WS-Security header entry. It immediately adds the header entry to the envelope. Then, it creates the username token and adds it to the header entry. Next it creates and adds the username element, and sets the username value at the node. We can change the order (for example, create the elements all at once and then add) and still get the same result.

These steps exactly mimic the ones on the server-side. Of course, the details of how we got the username are skipped in this illustration. For full details, please look at the source code at http://www.manning.com/kanneganti.

By now, you have learned how to write handler code. What you have not seen is how this code is added to the server or the client. Before showing how we can make handlers a part of server or the client, we will explore the concept of multiple handlers and how they can be chained. This concept is useful as we proceed to add more and more headers to the message. Finally, we will show the configuration of the handlers to the server or the client in full generality.

3.4.5. Handler chains

Handlers can be used for various kinds of tasks. In our example, we are using handlers to accomplish one task: separating the code that deals with the extraction of a user’s identity claim from the main service code. If there are multiple tasks, we can still use one single handler to deal with all those other than the core business logic of the service. However, that is not modular, and may lead to maintainability problems. Instead, we can use handler chaining to “hook up” multiple handlers to the server or the client.

For example: On the client-side, one handler may add a WS-Security header and another might encrypt the username and password in the WS-Security header to keep them safe. The reverse may happen on the server-side: a decryption handler followed by an authentication handler to verify the username and password provided by the client. We may even want to invoke the same handler more than once when processing a message. For example, we may call an encryption handler multiple times to encrypt different parts of a message.

JAX-RPC provides for associating a chain of handlers with each service. We will show how this association happens in the next section. For now, let us see how the handler chains are invoked on the client and server-sides.

Since there are multiple handlers touching a message, there ought to be rules about how they interact. Without implying any particular order, the following rules specify how the handlers behave.

  1. Any information saved in the MessageContext is visible to every handler in the chain as well as to the service. In example 2 (listings 3.3 and 3.4), we already saw how to set data in MessageContext and read it back.
  2. A handler may return true from handleRequest, handleResponse, and handleFault to indicate that the next handler in the chain should be invoked. In case no more handlers are left, the message is dispatched to the endpoint. As shown in figure 3.8, handlers in a chain are called in reverse order for processing responses and faults compared to the order in which they are called for processing requests.
    Figure 3.8. A chain of JAX-RPC handlers can be invoked on the client as well as the server-side. Handlers in a chain are called in reverse order for processing responses and faults compared to the order in which they are called for processing requests.

  3. If a handler returns false from handleRequest, no more handlers in the chain are called to handle the request. The service endpoint is not called either. Instead, the handler returning false from handleRequest has the responsibility of creating the response message. The handleResponse methods of the handlers in the chain are called in the reverse order, starting with the handler that returned false from handleRequest. For example, in the server-side handler chain shown in figure 3.8, if the handleRequest method of handler Y returns false, instead of calling the handleRequest method of handler Z next as part of request processing, the JAXRPC engine switches to response processing and calls the handleResponse methods of handler Y and handler X, in that order.
  4. If a handler returns false from handleResponse, no more handlers in the chain are called. The response message is dispatched to the endpoint. For example, in the client-side handler chain shown in figure 3.8, if the handleResponse method of handler C returns false, the JAX-RPC engine will skip the handleResponse methods in handles B and A and directly deliver the response to the client endpoint.
  5. If a server-side handler throws a SOAPFaultException from handleRequest, the rest of the handlers in the chain and the service endpoint are not called to handle the request. Instead, the handleFault methods of the handlers in the chain are called in the reverse order, starting with the handler that threw SOAPFaultException from handleRequest. The handler throwing the exception has the responsibility of creating a SOAP fault in the response. (This rule is similar to rule 3.)
  6. If a server-side handler throws an exception other than SOAPFaultException, the request processing is terminated. The JAX-RPC implementation generates a server SOAP fault by itself and dispatches it to the endpoint. (This rule is similar to rule 4.)
  7. The JAX-RPC specification rules that a client-side handler should not throw a SOAPFaultException. If a client-side handler throws an exception other than SOAPFaultException, the exception is propagated back to the client endpoint as an instance of java.rmi.RemoteException or any of its subclasses.

Now, we get back to the issue of how to add handlers to the actual service. In the next section we will show the details.

3.4.6. Configuring handlers and handler chains

The mechanism to configure handlers and handler chains differs between the server-side and the client-side.

Server-side configuration

On the server-side, handlers and handler chains can be configured using deployment descriptors specific to the JAX-RPC implementation. For example, Axis provides the syntax for configuring handlers and handler chains in its Web Service Deployment Descriptors (WSDD). Listing 3.6 shows the Axis WSDD for a service with two handlers arranged into a chain.

Listing 3.6. Axis Web Service Deployment Descriptor (WSDD) for a service with two handlers arranged in a chain

In addition to showing a handler chain, this listing illustrates two important aspects of configuring JAX-RPC handlers. Deployment descriptors of some JAX-RPC implementations such as Axis may require declaration of:

  • Namespace qualified names of one or more SOAP headers consumed by a handler
  • URIs for all the SOAP actors a handler chain represents.

That’s all there is to configuring server-side handlers and handler chains. Let us now shift our focus to configuring client-side handlers and handler chains.

Client-side configuration

JAX-RPC provides a programmatic API for configuring client-side handlers and handler chains. Example code in com.manning.samples.soasecimpl.example2.BrokerageServiceTestCase illustrates the API to use in client applications that employ statically generated stubs, dynamic invocation interface (DII), and dynamic proxies. Listing 3.7 is an extract that shows how to configure handlers and handler chains for a client that uses DII to invoke a web service.

Listing 3.7. Configuring handlers on the client-side for clients using DLL

JAX-RPC organizes handler chains by service instance and port name. We first need to obtain a reference to the service instance from the service factory . Once we get the service instance reference, we see if there is an existing handler chain for the port we are going to use. If none exists, we add a new handler chain . Then, we configure a handler by providing the parameter and value . If you’ll recall, in the server-side, we set these in the deployment descriptor file.

Finally, we add the handler to the chain . Now, if we create a call to the service, the client-side chain we have configured is used. If there is any information, such as the username here, that we want to make available to the handlers in the chain, we add that to the call as properties . The handlers will be able to access the call properties via the message context.

As explained in chapter 2, the client code can use WSDL either dynamically or statically. Listing 3.7 demonstrates how you can set up a client-side handler chain during dynamic invocation. If we are going to use static stubs, the code for setting up a client-side handler chain will be a little different. Let us see how. All the generated stubs are required by JAX-RPC to implement the javax.xml.rpc.Stub interface. The Stub interface provides a _setProperty method to set the username to be used. In addition, the JAX-RPC implementation will provide a custom API to get to the underlying Service instance and portname. Listing 3.8 shows the APIs provided by Axis-generated stubs.

Listing 3.8. Configuring handlers on the client-side for clients using Axis-generated stubs

The essential code to configure a client-side handler chain remains the same as the DII code in listing 3.7. The details of how we get the service and the port , differ in this case. Just like in the case of DII, we can pass information from the client to the client-side handlers by setting properties on the call instance. Since all the stub implementations implement the javax.xml.rpc.Stub interface, we can use its _setProperty method to do this .

Configuring handlers and handler chains for dynamic proxies is a little more involved. For an example, please look at the source code for the testDynamicProxy() method in BrokerageServiceTestCase.

In this section, with the help of an example, we have described how you can add handlers to a JAX-RPC SOAP engine to process SOAP extensions such as WS-Security, reducing the burden of handling SOAP extensions from the end services. As we pointed out before, this idea of processing SOAP extensions by adding handlers to the SOAP engine is not limited to JAX-RPC-based SOAP engines. For example, .NET also provides a similar mechanism named SOAPExtension.

It is not always possible or desirable to add handlers to a SOAP engine for processing SOAP extensions. For instance, an enterprise may use a number of SOAP engines to host a large number of services. Adding handlers to each SOAP engine may be too intrusive a solution to use in such environments. However, as WS-Security is a standard extension, almost every SOAP engine may come preconfigured with handlers to process WS-Security. Even then, there may be good reasons for processing WS-Security and some of the other SOAP extensions using intermediaries. For example, an enterprise may want to centralize security enforcement and not leave it up to every SOAP engine for enforcing appropriate levels of security.

In the next section, we will describe how this centralization can be done using intermediaries—that is, SOAP-processing nodes that are neither the source nor the destination for a SOAP message.

3.5. Processing SOAP extensions using intermediaries

Intercepting messages in transit and acting upon them is not without precedent. HTTP proxies are quite commonplace; they intercept HTTP requests in order to apply security policies and/or return cached responses. In fact, the SOAP specification explicitly supports the use of one or more intermediaries (such as a security service) in the message path by laying down specific rules that describe what an intermediary can and cannot do. In this section, we will introduce you to these rules.

But before we do that, we will address a question that might be bothering you at this point. Up until this point in the book, we have only showed you interactions between two endpoints. We showed you senders (or source endpoint) of SOAP messages directly connecting to the intended recipient (or the destination endpoint) for each message. How then, you may rightly wonder, does a message get routed via intermediaries? Two possibilities exist.

  1. The first possibility is that a network device that understands application-level semantics intercepts each message and routes it across the right set of intermediaries. But do such network devices exist? Yes, they do, and they are commonly referred to as Application-Oriented Networking (AON) devices. Appendix E describes AON in more detail.
  2. The second possibility is that the source endpoint connects to the first intermediary and not the destination endpoint when sending a message. The first intermediary can then do its work and pass on the message to a second intermediary. The second can then pass it to a third, the third can pass to a fourth, and so on until the last intermediary, which passes the message to the destination endpoint. How does each SOAP processing node (by node, we mean endpoint or intermediary) in the message path know what the next node should be? For very good reasons, there is no concrete answer to this question except in one special case. In general, it is up to a SOAP processing node (be it the source endpoint or an intermediary) to figure out where it will route the message next. However, as the last intermediary in a SOAP message path would almost always want to route the message to the originally intended destination endpoint, a specification named WS-Addressing provides a way to preserve the destination endpoint address as part of a message.

Next we will describe WS-Addressing. Subsequently, we will describe SOAP processing rules for intermediaries, which tell us what the intermediaries can and cannot do.

3.5.1. Preserving the endpoint information: WS-Addressing

Let us examine what happens at an intermediary such as a security service. The intermediary receives a message and reads the parts intended for it. It will, optionally, modify the message. For example, the intermediary may insert some new Header elements. Later, the intermediary will send the message to the next hop in the message-processing path, as shown in the figure 3.9.

Figure 3.9. Without intermediaries in a message path, no addressing information needs to be provided in the envelope. The introduction of intermediaries will however require that the destination endpoint information be preserved so that the final intermediary can route the message to the destination endpoint.

As you can see, an intermediary should be able to figure out where the message should go next and route the message to that hop. In general, intermediaries are free to determine the next hop the message should make. However, the last intermediary in a message path usually wants to route the message to its destination point. We say usually instead of always, as the last intermediary is free to route the message to a different destination than what the source endpoint asked for. For example, a message may get routed to a backup service instance in case the main service instance is down.

Clearly, the last intermediary needs to know the destination endpoint address. Of course, as shown in figure 3.9, this issue does not come up if there are no intermediaries. The source endpoint establishes a direct connection to the destination endpoint and the transport protocol itself handles the responsibility of routing the message to its destination. In a multihop message path, this is not the case. Responsibility of the first transport connection ends once it delivers a message to the first intermediary. Additional transport connections will have to be set up from the first intermediary to the second, second to third, and so on.

To allow the message to be routed to the final destination, we need a way of preserving the destination endpoint information for use by the last intermediary. WS-Addressing provides the needed standards here.

Listing 3.9 shows WS-Addressing in action.

Listing 3.9. WS-Addressing elements declare destination endpoint address whereas transport (HTTP) headers declare next hop address

HTTP is the transport protocol in this example. The HTTP headers show that the HTTP connection is made to the next hop, http://localhost:8000/axis/services/proxy, with the SOAPAction header set to an empty string. The ultimate destination’s address and SOAPAction parameter are different from these and preserved using To and Action headers defined by WS-Addressing.

WS-Addressing can also be used to convey the reply-to address, message ID, and correlation ID. The reply-to address is useful when using asynchronous messaging as SOAP transport. Message ID and correlation ID are also useful for replying to a particular message asynchronously.

Now that you understand WS-Addressing, we will get back, as promised, to explaining the rules SOAP lays down for message processing in intermediaries.

3.5.2. SOAP processing rules for intermediaries

SOAP explicitly acknowledges the possibility of intermediaries. Doing so enables a rich extension model. The fact that different nodes can take different actions on a SOAP message can help us develop horizontal services. For example, one intermediary node may take care of regulatory compliance whereas another intermediary can take care of security concerns.

In this section, we will see the message processing rules SOAP specifies to accommodate the possibility of multiple intermediaries in a SOAP message path.

Addressing a node in SOAP

SOAP makes it easy for a dynamic network of processing nodes (intermediaries + endpoint) to work together without conflicts by allowing each to clearly see what parts of a message are intended for it and what are not. As we explained earlier in this chapter, SOAP 1.1 defines an optional actor attribute (renamed role in SOAP 1.2) to indicate who should process a header entry. This facility makes it easy to partition the SOAP header entries into sets that should be processed by different nodes in the message path.

For example, an intermediary node that can take care of regulatory compliance can be explicitly fed the required data using a header that is targeted at it. All it takes is to simply set the entry’s actor attribute to an URI that identifies the node to target it.

Typically, we set the actor attribute to an explicit URI when we know which specific node it is intended for. However, there are a few reserved actor URIs we can use for identifying nodes based on their position in the message path:

  • http://schemas.xmlsoap.org/soap/actor/next, defined by SOAP 1.1, targets a header entry at the next processing node. (The equivalent in SOAP 1.2 is http://www.w3.org/2003/05/soap-envelope/role/next.).
  • http://www.w3.org/2003/05/soap-envelope/role/ultimateReceiver is defined by SOAP 1.2 to explicitly target a header entry at the end recipient. Note that by default, if there is no actor, only the end recipient can act on it.
  • http://www.w3.org/2003/05/soap-envelope/role/none is a special value defined by SOAP 1.2 to indicate that a header entry should not be processed by any node. Any node is free to look at such an entry if another entry targeted at the node refers to the contents of the former. This is an excellent way to provide information to all the nodes—for example, we can keep a timestamp for all the nodes that need that information.
  • An empty string (“”) as a role in SOAP 1.2 is another special case, indicating that the base URI should be used. The base URI is specified explicitly using the attribute xml:base. If that attribute is not used, the default value for the base URI depends on the protocol used to carry SOAP messages. For HTTP, the base URI is the HTTP Request-URI or the value of the HTTP Content-Location header field.

In addition to providing a mechanism for addressing a specific node in the message path, SOAP lays down other rules that all SOAP processing nodes must comply with. We will explain these next.

Processing at a node

Once a node gets the message, it must comply with the following rules when processing the message:

  1. The node should remove the header entries targeted at it before the message is transmitted to the next node. SOAP 1.2 however introduces a relay attribute to indicate that an unprocessed header must be relayed on to subsequent nodes in the message path.
  2. As described earlier in this chapter, the node must raise a SOAP fault if it does not understand a header entry targeted at it with the mustUnderstand attribute set to "1."
  3. The node can add new header entries. For example, the node can add information that needs to be communicated to subsequent nodes in the message path. There are no restrictions on what kind of header entries a node might add. For example, a node can reinsert the header it just consumed if it is needed by a subsequent node in the message path. Of course, the actor attribute on the reinserted node should be adjusted to match a subsequent node’s URI.
  4. The node can modify any part of the message itself, including header entries not targeted at it and the Body. However, when doing so, it is good custom to indicate to subsequent nodes how the message is transformed. For example, if a security node encrypts part of a message, it should add a header entry describing which portions of the message have been encrypted, the algorithm used, and the key used to encrypt. A subsequent node can then use this information to decrypt the encrypted parts appropriately, provided it has access to the key needed to decrypt.

You now understand how SOAP accommodates for intermediaries in message paths. What you have learned in this section should have set you thinking about questions such as: can security be truly delegated off to an intermediary, and if so, when should I do that? We will return to these questions in chapter 8, as by then you will have learned enough about WS-Security to figure out what parts can be addressed by intermediaries and what cannot.

We will conclude this chapter by answering a few frequently asked questions about SOAP extensions.

3.6. SOAP Extensions FAQ

As you have seen with WS-Security, SOAP provides a convenient extension mechanism for addressing concerns that SOAP doesn’t take care of by itself. We can extend SOAP to take care of domain-independent concerns such as security and transactions, as well as domain-specific concerns such as metering and billing. Extending SOAP with headers is thus a powerful design pattern that needs to be mastered by practitioners of SOA.

In this section, we will answer some of the frequently asked questions about the usage of headers and handlers when extending SOAP. Note that this section is here for the sake of completeness and is not directly related to security in SOA.

3.6.1. What should go into the headers?

Technically, whatever you can do using the SOAP body can be done in headers. For example, the whole message body can be thought of as a header targeted at the final destination with mustUnderstand set to "1." In that case, which parts of a message should be in the headers and which parts should be in the body?

A rule of thumb is to use the SOAP message body only for information needed by the core business logic of the service. For example, if you are invoking the brokerage service to get a quote for a stock symbol, only the stock symbol belongs in the body.

What else would one want to send with a quote request anyway? You may want to send your premium account number so that the brokerage service responds faster and/or with better information. For example, the brokerage may offer premium account holders the latest quotes whereas everyone else may be provided with delayed quotes.

Typically, information in headers is utilized by some functionality that is common across a number of services. That functionality, residing perhaps in a handler (or another process as you will see in chapter 8), can access these header entries and process them. For example, a billing handler or process may meter the usage of services by customers. It may obtain the customer account number from a header and the name of the service from the body. Figure 3.10 shows this pattern of utilizing headers for enabling common services.

Figure 3.10. Headers are often utilized to enable common services such as security and billing.

Clients, either directly or via handlers, may add headers that common services such as security, billing, and auditing may utilize. Once the common services utilize the information available in the headers, they may remove the headers from the message and forward the request to the appropriate end service.

Several vendors provide solutions for implementing common services. For example, ESB vendors provide for centralization of common services.

3.6.2. How do we standardize on headers?

Since creating a namespace is easy, the temptation is to define as many headers as we require in our own namespace. However, we must remember one thing: the headers are supposed to provide a standard way of extending SOAP to implement specific functionality. If the functionality we wish to enable via an extension has already been addressed by a standard extension, we are better off sticking to the header entries defined by the standard extension.

For example, you should not create your own headers for carrying username and password, unless the meaning is drastically different from the WS-Security standard. In most cases, if the meaning is different, perhaps the purpose of the Header element and the name also is different enough to create unambiguous header names.

3.6.3. How many handlers?

How many handlers should we use? If we go for modularity, we should use different handlers for different tasks. That lets us mix and match the handlers via configuration mechanisms. However, performance reasons may make us put multiple tasks in one handler. Also, interdependencies between the two handlers may require us to merge them into one. You will see examples of these kinds later in the book.

3.6.4. How do we support handlers?

Ultimately clients have to supply the headers with requests. Since most of the information may be specific to the client, it may not be possible to write a separate process to add header entries. What this means is that the code to add header entries should be part of the client itself, since it needs access to the information only the client can provide.

Even though providing and consuming header entries is standard, it is not easy to program. Typically, in enterprises, standard libraries are provided so that the clients are spared the complexity of the coding. If you are designing custom headers for an enterprise, you should consider providing the required libraries too. The libraries may be packaged in the form of handlers if the enterprise predominantly uses JAX-RPC.

3.7. Summary

In this chapter, we first argued that the right approach for addressing security in SOAP is to do it via an extension to SOAP. We then described how SOAP allows itself to be extended via headers and introduced WS-Security, a standard SOAP extension to carry security tokens and ensure message-level security. We showed you how to produce and consume WS-Security-related (and other) header entries by adding handlers to a SOAP engine. Once you run the examples and study the code, you should be able to write the handlers required to process any header entries.

We also introduced the notion of SOAP intermediaries and described how SOAP messages can be routed across intermediaries using WS-Addressing. We described the rules laid down by SOAP for intermediaries and hinted at the possibility of delegating the responsibility of security enforcement to an intermediary. We will develop this idea further in chapter 8.

Toward the end, we provided guidelines for you to develop standard SOAP headers for your enterprise.

Now that you understand SOAP headers and how to process them, you can see them in action. Specifically, you will learn how to use them for authentication in chapters 4 and 5. You will also see how these headers can be used for encryption in chapter 6 and signatures in chapter 7. In all those examples, we are going to assume familiarity with handlers and will not explain that part of the code.

Suggestions for further reading

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
13.59.173.242