Tuesday, September 21, 2010

Camel in Action – Book Review

ibsen_cover150

Recently, I reviewed MEAP edition of Camel in Action. I guess it was a last stage review, It is suppose to be released later this year. It was a very interesting and informative experience for me. Book is very well devised, provides seamless flow across chapters as we learn Camel.

The authors Claus Ibsen and Jonathan Anstey have provided Java DSL and Spring DSL for plugging in almost each and every processor whether the processor is one of the Enterprise Integration Pattern (EIP), or creating Routes, or one of Transformers or one of Components supported by Camel. They have very well defined Camel development for adding customized routes to Camel Context using Route Builder, intermediate routes the routing engine or adding one of around 80 components like File, FTP, CXF, JMS, JPA, Quartz, HTTP etc. They have taken a simple scenario of Rider Auto Parts, came up with fairly practical requirements and shown how Camel can be used to implement/configure the solutions for those requirements. Also, we get a comprehensive list of well-known data formats supported by Camel and their usage details. What I appreciate in Camel and also well explained in this book is good support for debugging your message, support for introducing mocking component and testing. My personal interest has been on CXF, I was happy to see good description of configuring CXF component via referencing a bean and configuring it by URI. Authors have diligently shown both contract-first and code-first approaches. Every chapter and example refers to downloadable source code which can be run quickly with simple maven command. Even for creating your own projects many Camel’s maven archetypes are explained. A good point is Camel development is well supported by Eclipse IDE.

Beginners will learn many things what Camel is, what all it can do and how simple it is to use. For intermediate users, I feel they will get a hands on to some alternative ways of configuring and using Camel, Components, Data formatters and EIPs, monitoring and managing Camel. For advance users, I guess concurrency and transactions will be helpful in getting more insight about Camel.

Tuesday, May 18, 2010

Small facts about Generics

Small facts about Generics:



  • Type parameters are considered as non static typed variables; hence you can’t have static variable declaration or usage of typed variable in a static method.

  • Type parameters may hide one of actual already declared java type. Caution should be taken when declaring type variable name.

  • Compiler allows your declared type parameter to extend an already declared final java type, it just gives you a warning, no error, may be because to allow to hint and allow get only and put only operations respectively.

  • You may declare an entirely different typed parameter while creating an object and can work with it. But reflection on that object won’t give you expected actual instance types variables, it will give you the actual typed variables declared in the class declaration.

Saturday, May 01, 2010

ConcurrentModificationException - How to avoid / remove it?

As per the Java Doc:

This exception may be thrown by methods that have detected concurrent modification of an object when such modification is not permissible. For example, it is not generally permissible for one thread to modify a Collection while another thread is iterating over it.

Caused by Fail Fast Iterators, any collection using these iterators can throw the CME. They happen because of mainly 2 reasons -

  • The state of the iterator gets changed by the same/other thread in such a fashion that all other references feel that their understanding of the iterator's state is dirty. For instance, threadA is iterating using iterator.next() and some other threadB takes the reference of the iterator and removes some entry from the collection, hence threadA will get hinted that it's knowledge about iterator state is not right, in other words it has become dirty now. Even, one important point is that there is no requirement to have another thread to cause CME, it can happen because of the same thread itself. In single thread, it can happen when you are iterating over the collection and calling collectionImpl.remove or collectionImpl.add, which causes the iterator reference to feel like it has been fooled, as it's state is going to be changed.
  • Another reason could be that the underlying collection is not initialized and some other thread has started iterating over it.

A code like below will throw concurrent modification exception,

  1: import java.util.List;
  2: import java.util.ArrayList;
  3: import java.util.Iterator;
  4:
  5: public class Sample{
  6:
  7: List<String> strings = new ArrayList<String>();
  8:
  9: public void fillList(){
 10:  for(int i=0;i<10;i++){
 11:   strings.add(""+i);
 12:  }
 13: }
 14:
 15: public void iterateList(){
 16: /*WRONG WAY, will produce CME
 17: *Iterator reference is old,
 18: *iterator's idea of collections' state becomes dirty
 19: * after collectionImpl.remove/add/etc
 20: */
 21:  Iterator<String> itr = strings.iterator();
 22:  strings.remove("7");
 23:  while(itr.hasNext()){
 24:   System.out.println(itr.next());
 25:  }
 26: }
 27:
 28: public static void main(String args[]){
 29: Sample s = new Sample();
 30: s.fillList();
 31: s.iterateList();
 32: }
 33: }
 34: 


The solutions to avoid ConcurrentModificationException are as follows:



1. Use Weakly Consistent Iterators - JavaSE 1.5 and JavaSE 1.6 has many collection implementation which uses Weakly Consistent Iterators, which don't throw CME.




  • CopyOnWriteArraySet, CopyOnWriteArrayList (Java SE 5): They copy an internal array on each modification. Hence, make sure that when you are using these implementation your usage is more of iteration than modification to them.


  • ConcurrentSkipListSet, ConcurrentSkipListMap (Java SE 6): They are skip list based implementation, provides concurrency with sorting.


  • ConcurrentHashMap (Java SE 6): provides extra atomic methods.



2. Make sure you are using iterator in right way,



  1: import java.util.List;
  2: import java.util.ArrayList;
  3: import java.util.Iterator;
  4:
  5: public class Sample{
  6:
  7: List<String> strings = new ArrayList<String>();
  8:
  9: public void fillList(){
 10:  for(int i=0;i<10;i++){
 11:   strings.add(""+i);
 12:  }
 13: }
 14:
 15: public void iterateList(){
 16: // RIGHT WAY 1
 17: //Get a new reference to the iterator
 18:
 19: /*
 20:  strings.remove("7");
 21:  for(String str:strings){
 22:   System.out.println(str);
 23:  }
 24: */
 25:
 26:
 27: //OR RIGHT WAY 2
 28: // Try to remove the element from Iterator reference,
 29: // so that iterator doesn't become dirty
 30:
 31: /*
 32:  Iterator<String> itrNew = strings.iterator();
 33:  while(itrNew.hasNext()){
 34:  String str = itrNew.next();
 35:  if("7".equals(str)){
 36:    itrNew.remove();
 37:   }else{
 38:    System.out.println(str);
 39:   }
 40:  }
 41: */
 42:
 43:
 44: //OR RIGHT WAY 3, quite similar to RIGHT WAY 1
 45: //Get the itr reference after your collection modification operation
 46: /*
 47:  strings.remove("7");
 48:  Iterator<String> itrOther = strings.iterator();
 49:  while(itrOther.hasNext()){
 50:   System.out.println(itrOther.next());
 51:  }
 52: */
 53: }
 54:
 55: public static void main(String args[]){
 56:  Sample s = new Sample();
 57:  s.fillList();
 58:  s.iterateList();
 59: }
 60:
 61: }


3. Make sure that your collection instance are populated before your thread start iterating over them.



  1: class MyClass {
  2:
  3: private final List myList = makeList();
  4:
  5: private static list makeList() {
  6:  List list = new ArrayList();
  7:  // do what you need to initialize this 
  8:  return list;
  9:  }
 10: }
 11: 


ConcurrentSet are not included in Java 1.6, as Collections class provides a convenient method newSetFromMap which returns a set backed by map.



If you want you can use Decorator pattern to write a ConcurrentSet which takes a regular Set are constructor arguments and inside the class uses a ConcurrentHashMap<E, BOOLEAN> to give concurrent set.

Wednesday, April 21, 2010

Linux Shell script to find the process listening on a given port

port=$1
procinfo=$(netstat --numeric-ports -nlp 2> /dev/null grep ^tcp grep -w ${port} tail -n 1 awk '{print $7}')
case "${procinfo}" in
"")
echo "No process listening on port ${port}"
;;
"-")
echo "Process is running on ${port}, but current user does not have rights to see process information."
;;
*)
echo "${procinfo} is running on port ${port}"
ps -uwep ${procinfo%%/*}
;;
esac

Wednesday, February 10, 2010

Ctrl-S hanged vi editor

This has been the standard almost since the beginning of time.

Ctrl S is the XOFF character, uses for flow control on serial links that do not have hardware flow control. It doesn't freeze the output...
Receipt of the XON character (Ctrl Q) disables the flow control, and commands output to continue.

Saturday, August 15, 2009

MTOM/XOP and performance improvements in CXF

Message Transmission Optimization Mechanism (MTOM) is a core feature of web service engine. CXF supports MTOM with XOP.

Brief description about MTOM/XOP in SOAP:

In standard SOAP messages, binary objects are base64-encoded and included in the message body. This increases their size by 33%, which for very large binary objects can significantly impact transmission time. The SOAP Message Transmission Optimization Mechanism (MTOM) and XML-binary Optimized Packaging (XOP) specifications, define a method for optimizing the transmission of large base64Binary data objects within SOAP messages:

XOP is used as the referencing mechanism in the serialised XML infoset. In theory, the abstract MTOM model could be used with a different referencing mechanism and/or different container format, over a different transport protocol instead of HTTP. In practice, MTOM is usually used with XOP, MIME and HTTP.

In MTOM, an Optimized MIME Multipart/Related Serialization of SOAP Messages is defined that summarises that the serialized XML infoset will include XML-binary Optimized Packaging (XOP) in place of the binary data, and the binary data (along with the serialized XML infoset with XOP placeholders) will be represented together in a MIME container.

Performance issue description: In CXF 2.0.7, MTOM performance was poor. In the initial set of tests I had done, For a 12 MB of data, it was taking around 1.2-1.4 seconds. Pretty Slow compared to other WS stacks MTOM performance.

Sharing approach: We intergrated CXF in Pramati Java EE 1.5 application server. I delved into this, firstly removed all in and out application server's (web container streams). removed out CXF Interceptors to finally come to the one which composes and decomposes MTOM SOAP message, to finally arrive at MimeBodyPartInputStream, PushbackInputStream.

MimeBodyPartInputStream doesn't implements read(byte[]) method, hence it delegates it to parent InputStream class. InputStream's read(byte[]) runs over a loop, eventually delegating to PushBackInputStream, which reads a single byte and performs boundary matching over that Byte.

A simple test program which takes the time taken by the MimeBodyPartInputStream to read from a loaded buffer shows that MimeBodyPartInputStream takes ~1200-1400 ms to read a 12MB buffer. On the other hand, an InputStream takes around ~100-150ms to do so. Yes, that's obvious as we all understand that MimeBodyPartInputStream has the logic of detecting a probable boundary and it performs multiple if checks to do so, also it calls read and unread over PushBackInputStream. But again considering number of the reads and unreads also, the time of MimeBodyPartInputStream looked poor.

An alternative implementation of MimeBodyPartInputStream which added dynamic buffer creation, buffer used for forward-backward index movement, and implements read(byte[] buffer, int off, int len) helped me to solve the performance problem. The functionality of reading the buffer, matching the process boundary is now performed by it.

The performance counters after the changes were (12 MB of data):

1. ~1578 ms (current CXF MBPIS)
2. ~172 ms (just read raw 12MB data)
3. ~188 ms (new CXF MBPIS)

They look more encouraging, sensible and charming :)

So next time you use MTOM feature in any CXF releases 2.0.10 or 2.1.4 after, you will get better performance.

In case you want to see the changes, they are below,

Index: trunk/rt/core/src/main/java/org/apache/cxf/attachment/MimeBodyPartInputStream.java
===================================================================
diff -u -N -r651669 -r718620
--- trunk/rt/core/src/main/java/org/apache/cxf/attachment/MimeBodyPartInputStream.java  
(.../branches/2.0.x-fixes/rt/core/src/main/java/org/apache/cxf/attachment/MimeBodyPartInputStream.java)  (revision 651669)
+++ trunk/rt/core/src/main/java/org/apache/cxf/attachment/MimeBodyPartInputStream.java  
(.../trunk/rt/core/src/main/java/org/apache/cxf/attachment/MimeBodyPartInputStream.java)  (revision 718620)
@@ -28,15 +28,159 @@
     PushbackInputStream inStream;
 
     boolean boundaryFound;
-
+    int pbAmount;
     byte[] boundary;
+    byte[] boundaryBuffer;
 
-    public MimeBodyPartInputStream(PushbackInputStream inStreamParam, byte[] boundaryParam) {
+    public MimeBodyPartInputStream(PushbackInputStream inStreamParam, 
+                                   byte[] boundaryParam,
+                                   int pbsize) {
         super();
         this.inStream = inStreamParam;
         this.boundary = boundaryParam;
+        this.pbAmount = pbsize;
     }
 
+    public int read(byte buf[], int origOff, int origLen) throws IOException {
+        byte b[] = buf;
+        int off = origOff;
+        int len = origLen;
+        if (boundaryFound) {
+            return -1;
+        }
+        if ((off < 0) || (off > b.length) || (len < 0) 
+            || ((off + len) > b.length) || ((off + len) < 0)) {
+
+            throw new IndexOutOfBoundsException();
+        }
+        if (len == 0) {
+            return 0;
+        }
+        boolean bufferCreated = false;
+        if (len < boundary.length * 2) {
+            //buffer is too short to detect boundaries with it.  We'll need to create a larger buffer   
+            bufferCreated = true;
+            if (boundaryBuffer == null) {
+                boundaryBuffer = new byte[boundary.length * 2];
+            }
+            b = boundaryBuffer;
+            off = 0;
+            len = boundaryBuffer.length;
+        }
+        if (len > pbAmount) {
+            len = pbAmount;  //can only pushback that much so make sure we can
+        }
+        if (len > 0) {
+            len = inStream.read(b, off, len);
+        }
+        int i = processBuffer(b, off, len);
+        if (bufferCreated && i > 0) {
+            // read more than we need, push it back
+            if (origLen >= i) {
+                System.arraycopy(b, 0, buf, origOff, i);
+            } else {
+                System.arraycopy(b, 0, buf, origOff, origLen);
+                inStream.unread(b, origLen, i - origLen);
+                i = origLen;
+            }
+        } else if (i == 0 && boundaryFound) {
+            return -1;
+        }
+        return i;
+    }
+
+    //Has Data after encountering CRLF
+    private boolean hasData(byte[] b, int initialPointer, int pointer, int off, int len)
+        throws IOException {
+        if (pointer < (off + len)) {
+            return true;
+        } else {
+            inStream.unread(b, initialPointer, (off + len) - initialPointer);
+            return false;
+        }
+    }
+
+    protected int processBuffer(byte[] buffer, int off, int len) throws IOException {
+        for (int i = off; i < (off + len); i++) {
+            boolean needUnread0d0a = false;
+            int value = buffer[i];
+            int initialI = i;
+            if (value == 13) {
+                if (!hasData(buffer, initialI, initialI + 1, off, len)) {
+                    return initialI - off;
+                }
+                value = buffer[initialI + 1];
+                if (value != 10) {
+                    continue;
+                } else {  //if it comes here then 13, 10 are values and will try to match boundaries
+                    if (!hasData(buffer, initialI, initialI + 2, off, len)) {
+                        return initialI - off;
+                    }
+                    value = buffer[initialI + 2];
+                    if ((byte) value != boundary[0]) {
+                        i++;
+                        continue;
+                    } else { //13, 10, boundaries first value matched
+                        needUnread0d0a = true;
+                        i += 2; //i after this points to boundary[0] element
+                    }
+                }
+            } else if (value != boundary[0]) {
+                continue;
+            }
+
+            int boundaryIndex = 0;
+            while ((boundaryIndex < boundary.length) && (value == boundary[boundaryIndex])) {
+                if (!hasData(buffer, initialI, i + 1, off, len)) {
+                    return initialI - off;
+                }                
+                value = buffer[++i];
+                boundaryIndex++;
+            }
+            if (boundaryIndex == boundary.length) {
+                // read the end of line character
+                if (initialI != off) {
+                    i = 1000000000;
+                }
+                if (!hasData(buffer, initialI, i + 1, off, len)) {
+                    return initialI - off;
+                }
+                boundaryFound = true;
+                int j = i + 1;
+                if (j < len && buffer[j] == 45 && value == 45) {
+                    // Last mime boundary should have a succeeding "--"
+                    // as we are on it, read the terminating CRLF
+                    i += 2;
+                    //last mime boundary
+                }
+
+                //boundary matched (may or may not be last mime boundary)
+                int processed = initialI - off;
+                if ((len - (i + 2)) > 0) {
+                    inStream.unread(buffer, i + 2, len - (i + 2));
+                }
+                return processed;
+            }
+
+            // Boundary not found. Restoring bytes skipped.
+            // write first skipped byte, push back the rest
+            if (value != -1) { //pushing back first byte of boundary
+                // Stream might have ended
+                i--;
+            }
+            if (needUnread0d0a) { //Pushing all,  returning 13
+                i = i - boundaryIndex;
+                i--; //for 10
+                value = 13;
+            } else {
+                i = i - boundaryIndex;
+                i++;
+                value = boundary[0];
+            }
+        }
+        return len;
+    }
+
     public int read() throws IOException {
         boolean needUnread0d0a = false;
         if (boundaryFound) {
@@ -77,8 +221,9 @@
         if (boundaryIndex == boundary.length) {
             // boundary found
             boundaryFound = true;
+            int dashNext = inStream.read();
             // read the end of line character
-            if (inStream.read() == 45 && value == 45) {
+            if (dashNext == 45 && value == 45) {
                 // Last mime boundary should have a succeeding "--"
                 // as we are on it, read the terminating CRLF
                 inStream.read();

Monday, July 06, 2009

Examples of WS-Security using CXF and WSS4J

If you are searching for some simple examples to understand and write WS-Security stuff (UsernameToken, Timestamp, Signature or Encryption) actions. I filed a jira task on JIRA, made some examples and Dan committed them in the svn. You can get them in CXF 2.2.3 distribution.
You can check the following (all included Timestamp action):

To get more detailed description about how it all works you can read this Configuring CXF for WS-Security... . I hope your initial queries, doubts while creating and understanding startup examples of WS-Security using CXF and WSS4J will be answered there :)

Monday, May 18, 2009

Specifying WS-SecurityPolicy, RM, Policy in a WSDL file

WS-Policy provides a way for the provider of a web service to convey conditions under which it provides the service. A invoker might use this policy to decide whether to use or not to use the service.WS-Policy just gives basic assertion support like, <wsp:all></wsp:all>, <wsp:exactlyone></wsp:exactlyone>to express one set of policy or alternatives too. Any conditions/requirements as assertions under <wsp:all></wsp:all>become mandatory,where as assertions inside <wsp:exactlyone></wsp:exactlyone>are considered as alternatives to each other.You can read more about various combinations/interactions/alternative in OASIS WS-PolicySpecification[1].


  • You can specify these WS-Poilcy assertions either inside input , output,fault, operation, port, or in binding wsdl elements.
  • You can either put them directly as child elements of them, or else you can refer them using <wsp:PolicyReference> element.

Policy can be attached as described by WS-PolicyAttached [4] at following levels:

  • Service Level: {Applied at <wsdl:Service>} - A policy associated with a service policy subject applies to any message exchange using any of the endpoints offered by that service.

  • Endpoint Level: {Applied at <wsdl:port> or <wsdl:portType> or <wsdl:binding>} - Since <wsdl:portType> can be used with multiple Bindings, hence it is RECOMMENDED to specify only abstract policy (binding independent) at this <wsdl:portType>. I prefer to use the other two options <wsdl:port> or <wsdl:binding> to apply endpoint policy. Policies associated with an endpoint policy subject apply to any message exchange made using that endpoint.

  • Operation Level: {Applied at <wsdl:portType/wsdl:operation> or <wsdl:binding/wsdl:operation>} - Policies associated with an operation policy subject apply to the message exchange described by that operation. Again, it is RECOMMENDED to specify only abstract policy at <wsdl:portType/wsdl:operation>, hence <wsdl:binding/wsdl:operation> is a prefered place to specify operation level policies.

  • Message Level: {Applied at <wsdl:message> or <wsdl:portType/wsdl:operation/wsdl:input> or <wsdl:portType/wsdl:operation/wsdl:output> or <wsdl:portType/wsdl:operation/wsdl:fault> or <wsdl:binding/wsdl:operation/wsdl:input> or <wsdl:binding/wsdl:operation/wsdl:output> or <wsdl:binding/wsdl:operation/wsdl:fault>} - Policies associated with a message policy subject apply to that message (i.e. input, output or fault message).

WS-Security Policy [2], WS-RM [3] assertions are build on top of WS-Policy for specifying security or reliable messaging requirements/constraints for aservice. For example, specifying security requirements for outgoing message, I can write as,

<wsp:Policy wsu:Id="Output_Policy">
<wsp:ExactlyOne>
<wsp:All>
<sp:SignedParts xmlns:sp="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy">
<sp:Body/>
</sp:SignedParts>
<sp:EncryptedParts xmlns:sp="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy">
<wsu:Timestamp/>
</sp:EncryptedParts>
</wsp:All>
</wsp:ExactlyOne>
</wsp:Policy>


and I can refer this policy as,

<wsdl:binding name="WebTransactionServiceSoapBinding"
type="tns:CreditCard">
<soap:binding style="document"
transport="http://schemas.xmlsoap.org/soap/http"/>
<!--wsp:PolicyReference URI="#Endpoint_Policy"/-->
<wsdl:operation name="purchase">
<soap:operation soapAction="" style="document"/>
<wsdl:input name="purchase">
<!--wsp:PolicyReference URI="#Input_Policy"/-->
<soap:body use="literal"/>
</wsdl:input>
<wsdl:output name="purchaseResponse">
<wsp:PolicyReference URI="#Output_Policy"/>
<soap:body use="literal"/>
</wsdl:output>
</wsdl:operation>
</wsdl:binding>

or specifying RM assertions as Embedded instead of referred can be,

<wsdl:service name="CartSLSBBeanService">
<wsdl:port binding="ns1:CartSLSBBeanServiceSoapBinding"
name="CartSLSBBeanPort">
<wswa:UsingAddressing
xmlns:wswa="http://www.w3.org/2005/02/addressing/wsdl"/>
<soap:address location=" http://localhost:8181/cart/cart"/>
<wsp:Policy xmlns:wsp="http://www.w3.org/2006/07/ws-policy"
xmlns:wsu="
http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" wsu:Id="RM">
<wsam:Addressing
xmlns:wsam=http://www.w3.org/2007/02/addressing/metadata>
<wsrmp:RMAssertion
xmlns:wsrmp=http://schemas.xmlsoap.org/ws/2005/02/rm/policy>
<wsrmp:BaseRetransmissionInterval Milliseconds="10000"/>
</wsrmp:RMAssertion>
</wsp:Policy>
</wsdl:port>
</wsdl:service>

You can read more about WS-SecurityPolicy[2] and WS RM[3] so as to understand what these assertions actually specify.I hope this helps
[1]. http://www.w3.org/TR/ws-policy/
[2]. http://docs.oasis-open.org/ws-sx/ws-securitypolicy/v1.2/ws-securitypolicy.html
[3].http://docs.oasis-open.org/ws-rx/wsrmp/200608/wsrmp-1.1-spec-cd-04.html
[4]. http://www.w3.org/TR/ws-policy-attach/

Monday, May 11, 2009

Understanding WS-Trust and configuration in CXF

Apache CXF is a high-performance, extensible, Intuitive & Easy to Use open source services framework. CXF helps you build and develop services using frontend programming APIs, like JAX-WS. CXF supports a variety of web service standards including SOAP, the Basic Profile, WSDL, WS-Addressing, WS-Policy, WS-ReliableMessaging, and WS-Security.

Apache CXF 2.2 is the third major release of CXF project. I found this release very interesting as it supports WS-SecurityPolicy and Partially supports WS-Trust. WS-Trust specifically deals with the issuing, renewing, and validating of security tokens, as well as with ways to establish, assess the presence of, and broker trust relationships between participants in a secure message exchange.

WS-SecurityPolicy is a very helpful and easier way of specifying your security requirements in an interoperable way. You can access a secured web service hosted on MS server by just pointing to the wsdl containing embedded WS-SecurityPolicy or a WS-Policy reference to a separate WS-SecurityPolicy file.

In CXF-2.2, WS-Trust is supported on client side, that means that now you can access a web services hosted by any WS vendor who requires you to produce tokens for authentication and authorization. For example, if I host a web service in Metro and configures a Metro STS (Secure Token Service - which provides tokens to clients). My CXF client will talk to Metro STS to acquire a token, once acquired CXF client can then produce this token to the Metro Service as an authentication and authorization token. An STS itself is a web service - a web service that issues security tokens.

Daniel Kulp has done a great job in making WS-Trust support up and working. In future release of CXF, we will come up with full support for WS-Trust. Any one who is interested can join the development I have filed a jira task for it.

How WS-Trust works: Basically on client side, ws-policy engine while parsing and understanding service wsdl, from <issuedtoken><issuer>... <issuer>assertion it learns that the service requires a security token to be produced. gives the WS-Addressing address of the STS service and WS-MEX (Metadata Exchange) address for getting the WSDL location of STS. STS may confirm the authenticity of the client who is requesting for the token. Based on the satisfactory confirmation of the authentication of the client, <issuedtoken> may have an assertion <requestsecuritytokentemplate> in which the service may specify what kind of RST request a client should make to STS, a service may specify it's particular requirements for the Token to be produced to it, the requirements can be KeySize, KeyType, TokenType, etc.

STS issues a RSTR (RequestSecurityTokenResponse) which contains requestedToken and proofkey. A proof key indicates proof of possession of the token associated with the requested security token. There are two types of proof keys: symmetric or asymmetric. A service can specify the proof key in the <keytype> element of <requestsecuritytokentemplate>.

In case of Symmetric key, STS creates and distributes the Symmetric key to both service and client. STS gives the key to the client in the <requestedprooftoken> element. STS gives the exact copy of the key to the service in the <keyinfo> element of the <subjectconfirmation> element in the issued SAML assertion in the RSTR response to the client. Client then forward the issued SAML assertion to the service.

In case of Public Key, client doesn't want to trust STS for issuing the secret key as proof of possession. In the RST (RequestSecurityToken) message client supplies RSA key or X.509 public key to STS. STS just embeds the RSA key or X.509 public key certificate in the <keyinfo> element of the <subjectconfirmation> element in the issued SAML assertion in the RSTR response to the client. Client then forward the issued SAML assertion to the service.

In case of No Proof Key, the issued token in <requestedsecuritytoken> itself works as proof of possession.

After getting RSTR, client composes the web service request as requested by WSDL requirements of the service. It embeds the SAML assertion into the request message to the service. Service and client uses the proof key for authentication and authorization of messages afterwards.

Configuring CXF for WS-Trust

Since currently only Client side support is provided in CXF 2.2 version (as I have discussed at the start of this blog entry), all we require to do is to configure a STSClient java class, org.apache.cxf.ws.security.trust.STSClient with the properties to wsdl location, service name, endpoint name. STSClient will look into wsdl, request for an issue, validate, renewal of the required token from STS and will put into the context of WS call so that finally the ws-request can be send with the required token, proof token and SAML assertion. Usually, you configure STS client in either of below two ways,

You can configure STSClient using code-first by creating a new instance of STSClient and calling setter methods of STSClient and finally setting a property "ws-security.sts.client" oof RequestContext() method on port instance as,

((BindingProvider)port).getRequestContext().put("ws-security.sts.client", stsinstance);

or, else you can configure spring bean as,

<jaxws:client name="{http://cxf.apache.org/}MyService">

<jaxws:properties>

<entry key="ws-security.sts.client">

<!-- direct STSClient config and creation -->

<bean class="org.apache.cxf.ws.security.trust.STSClient">

<constructor-arg ref="cxf"/>

<property name="wsdlLocation" value="target/wsdl/trust.wsdl"/>

<property name="serviceName" value="{http://cxf.apache.org/securitytokenservice}SecurityTokenService"/>

<property name="endpointName" value=""{http://cxf.apache.org/securitytokenservice}SecurityTokenEndpoint"/>

<property name="properties">

<map>

<entry key="ws-security.username" value="joe"/>

<entry key="ws-security.callback-handler" value="interop.client.KeystorePasswordCallback"/>

<entry key="ws-security.signature.properties" value="etc/alice.properties"/>

<entry key="ws-security.encryption.properties" value="etc/bob.properties"/> </map>

</property>

</bean>

</entry>

</jaxws:properties>

</jaxws:client>

Wednesday, January 21, 2009

Sample Annotation

A Novice Program for writing own Annotation. Annotations are not rocket science, they just have retention policy (runtime, source, class) and target (field, method, class, type, parameter) and finally can be looked using Reflection API.

MyAnnotation.java
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(value = RetentionPolicy.RUNTIME)

@Target(value = { ElementType.FIELD })

public abstract @interface MyAnnotation {
boolean enabled() default true;
String input() default "";
String output() default "";
int value() default -1;

}

Usage.java
import java.lang.reflect.Field;
public class Usage {
@MyAnnotation(input = "Hello")

public int a;
public void myMethod() {

Class<? extends Usage> c = this.getClass(); Field f = null;
try {
f = c.getField("a");
} catch (SecurityException e) { e.printStackTrace();
} catch (NoSuchFieldException e) { e.printStackTrace();
}
MyAnnotation ma = (MyAnnotation) f.getAnnotation(MyAnnotation.class);
System.out.println(ma.input());
}
public static void main(String args[]) {

Usage u = new Usage(); u.myMethod(); }
}

Sunday, September 21, 2008

Configuring CXF for Web Service Security using WSS4J

In case you directly want to see samples, you can go to Examples of WS-Security.....
You can read to below to understand bits, assuming you have a sample WS application using CXF. To secure that WS application you need to do following,

Create KeyStores and TrustStores
OpenSSL and Java SE 6 keytool creates X509v3 certificates, whereas Java SE 5 or earlier keytool creates X509v1 certificate. If you already have keystores and truststores and you are not sure about version of them, you can verify the version of your X509 certificate using this blog entry I blogged sometime back. Lets create new keystores and truststores with new X509 private and public key pair.
a) Creating Client Public and Private Key in Client keystore and Server Public and Private key in Server Keystore
keytool -genkey -alias clientX509v1 -keypass keypassword -storetype jks -storepass storepassword -validity 3650 -keyAlg RSA -keystore client-keystore.jks
keytool -genkey -alias serverX509v1 -keypass keypassword -storetype jks -storepass storepassword -validity 3650 -keyAlg RSA -keystore server-keystore.jks
b) Exporting clients public key to an external file and servers public key to an external file
keytool -export -alias clientX509v1 -file client-certfile.csr -keystore client-keystore.jks -storepass storepassword -keyAlg RSA
keytool -export -alias serverX509v1 -file server-certfile.csr -keystore server-keystore.jks -storepass storepassword -keyAlg RSA
c) Import the clients public certificate from the external file to server trust store and servers public certificate to the client trust store
keytool -import -noprompt -alias clientX509v1 -file client-certfile.csr -storepass storepassword -keystore server-truststore.jks -storetype JKS
keytool -import -noprompt -alias serverX509v1 -file server-certfile.csr -storepass storepassword -keystore client-truststore.jks -storetype JKS
Now we have required keystores and truststores with X509V1 certificates.

Configure CXF Bus:
Now we need to configure In and Out configuration of the server and client on CXF using spring. WSS4J provides security implementation for CXF, for security to be applied on XML content, CXF required SAAJ Interceptor which creates the SOAP document over which WSS4J works.

On Client

<jaxws:client
name="{http://apache.org/hello_world_soap_http}TimestampSignEncrypt";
createdFromAPI="true">
<jaxws:features>
<bean class="org.apache.cxf.feature.LoggingFeature"/>
</jaxws:features>

<jaxws:outInterceptors>
<bean class="org.apache.cxf.binding.soap.saaj.SAAJOutInterceptor"/>
<ref bean="TimestampSignEncrypt_Request"/>
</jaxws:outInterceptors>

<jaxws:inInterceptors>
<ref bean="TimestampSignEncrypt_Response"/>
<bean class="org.apache.cxf.binding.soap.saaj.SAAJInInterceptor"/>
</jaxws:inInterceptors>

</jaxws:client>

On Server

<jaxws:endpoint
name="{http://apache.org/hello_world_soap_http}TimestampSignEncrypt";
createdFromAPI="true">

<jaxws:features>
<bean class="org.apache.cxf.feature.LoggingFeature"/>
</jaxws:features>

<jaxws:outInterceptors>
<bean class="org.apache.cxf.binding.soap.saaj.SAAJOutInterceptor"/>
<ref bean="TimestampSignEncrypt_Response"/>
</jaxws:outInterceptors>

<jaxws:inInterceptors>
<ref bean="TimestampSignEncrypt_Request"/>
<bean class="org.apache.cxf.binding.soap.saaj.SAAJInInterceptor"/>
</jaxws:inInterceptors>

</jaxws:endpoint>

Above is the CXF Bus configuration on server and client to configure WSS4J, Log an SAAJ interceptors for both in and out configuration.

Provide Security Configuration
Now, we need to write Security configurations on server and client for in and out interceptors.
In this example, I have written all commonly used Actions; using Timestamp, Encrypting method argument, and sigining Timestamp and/or body. The order in which they are written is the order in which these actions are performed. Also, we need to configure user (signature) and encryption user accordingly on server and client. Also, crypto configurations needs to pass about keystore and truststore related information; by signaturePropFile and encryptionPropFile properties.

Below is the security related server side configuration configured in WSS4JInInterceptor and WSS4JOutInterceptor

For Server side outgoing response to Client

<bean class="org.apache.cxf.ws.security.wss4j.WSS4JOutInterceptor" id="TimestampSignEncrypt_Response">

<constructor-arg>
<map>
<entry key="action" value="Timestamp Signature Encrypt"/>
<entry key="user" value="service"/>
<entry key="signaturePropFile"
value="server_decrypt.properties"/>
<entry key="encryptionPropFile"
value="server_sign.properties"/>
<!--entry key="signatureKeyIdentifier" value="DirectReference"/-->
<!--entry key="encryptionKeyIdentifier" value="IssuerSerial" /-->
<entry key="passwordCallbackClass"
value="com.xyz.ws.security.KeystorePasswordCallback"/>
<entry key="signatureParts"
value="{Element}{http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd}Timestamp;{Element}{http://schemas.xmlsoap.org/soap/envelope/}Body"/>
<entry key="encryptionParts"
value="{Element}{http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd}Timestamp;{Element}{http://www.w3.org/2000/09/xmldsig#}Signature;{Content}{http://schemas.xmlsoap.org/soap/envelope/}Body"/>
<!--entry key="encryptionKeyTransportAlgorithm"
value="http://www.w3.org/2001/04/xmlenc#rsa-1_5"/-->
<!--entry key="encryptionSymAlgorithm"
value="http://www.w3.org/2001/04/xmlenc#aes128-cbc"/-->
</map>

</constructor-arg>
</bean>

For Server side incoming request from client

<bean class="org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor" id="TimestampSignEncrypt_Request">

<constructor-arg>
<map>
<entry key="action" value="Timestamp Signature Encrypt"/>
<entry key="signaturePropFile" value="server_sign.properties"/>
<entry key="decryptionPropFile" value="server_decrypt.properties"/>
<entry key="passwordCallbackClass"
value="com.xyz.ws.security.KeystorePasswordCallback"/>
</map>
</constructor-arg>

</bean>

Below is the client side security related configuration configured in WSS4JInInterceptor and WSS4JOutInterceptor

For Client side outgoing request to Server

<bean class="org.apache.cxf.ws.security.wss4j.WSS4JOutInterceptor" id="TimestampSignEncrypt_Request">

<constructor-arg>
<map>
<entry key="action" value="Timestamp Signature Encrypt"/>
<entry key="user" value="client"/>
<entry key="encryptionUser" value="service"/>
<entry key="signatureKeyIdentifier" value="DirectReference"/>
<entry key="signaturePropFile" value="client_sign.properties"/>
<entry key="encryptionPropFile" value="client_encrypt.properties"/>
<entry key="encryptionKeyIdentifier" value="IssuerSerial" />
<entry key="passwordCallbackClass"
value="com.xyz.ws.security.KeystorePasswordCallback"/>
<entry key="signatureParts"
value="{Element}{http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd}Timestamp;{Element}{http://schemas.xmlsoap.org/soap/envelope/}Body"/>
<entry key="encryptionParts"
value="{Element}{http://www.w3.org/2000/09/xmldsig#}Signature;{Content}{http://schemas.xmlsoap.org/soap/envelope/}Body"/>
<!--entry key="encryptionKeyTransportAlgorithm"
value="http://www.w3.org/2001/04/xmlenc#rsa-1_5"/-->
<!--entry key="encryptionSymAlgorithm"
value="http://www.w3.org/2001/04/xmlenc#aes128-cbc"/-->
</map>
</constructor-arg>

</bean>

For Client Side Incoming Response from Server:

<bean class="org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor"
id="TimestampSignEncrypt_Response">

<constructor-arg>
<map>
<entry key="action" value="Timestamp Signature Encrypt"/>
<entry key="signaturePropFile" value="client_encrypt.properties"/>

<entry key="decryptionPropFile" value="client_sign.properties"/>
<entry key="passwordCallbackClass"
value="com.xyz.ws.security.KeystorePasswordCallback"/>
</map>
</constructor-arg>

</bean>

Contents of crypto configuration files:
You require to give information about the keystore or truststore containing X509 private or public key, keystore password and alias name for the public-private key pair.

For encryption , you require to configure public key of the receiver, hence client/server truststore contains public certificate of server/client alias which is serverx509v1/clientx509v1 respectively.

For Signature, you require to use the private key stored in client/server keystore and hence alias clientx509v1/serverx509v1 respectively.

client_encrypt.properties
org.apache.ws.security.crypto.provider=org.apache.ws.security.components.crypto.Merlin
org.apache.ws.security.crypto.merlin.keystore.type=jks
org.apache.ws.security.crypto.merlin.keystore.password=storepassword
org.apache.ws.security.crypto.merlin.keystore.alias=serverx509v1
org.apache.ws.security.crypto.merlin.file=keystore/client-truststore.jks

client_sign.properties
org.apache.ws.security.crypto.provider=org.apache.ws.security.components.crypto.Merlin org.apache.ws.security.crypto.merlin.keystore.type=jks org.apache.ws.security.crypto.merlin.keystore.password=storepassword
org.apache.ws.security.crypto.merlin.keystore.alias=clientx509v1 org.apache.ws.security.crypto.merlin.file=keystore/client-keystore.jks

server_decrypt.properties
org.apache.ws.security.crypto.provider=org.apache.ws.security.components.crypto.Merlin org.apache.ws.security.crypto.merlin.keystore.type=jks org.apache.ws.security.crypto.merlin.keystore.password=storepassword org.apache.ws.security.crypto.merlin.keystore.alias=serverx509v1 org.apache.ws.security.crypto.merlin.file=keystore/server-keystore.jks

server_sign.properties
org.apache.ws.security.crypto.provider=org.apache.ws.security.components.crypto.Merlin org.apache.ws.security.crypto.merlin.keystore.type=jks org.apache.ws.security.crypto.merlin.keystore.password=storepassword
org.apache.ws.security.crypto.merlin.keystore.alias=clientx509v1 org.apache.ws.security.crypto.merlin.file=keystore/aerver-truststore.jks

Install Bouncy Castle Security Provider
Just check the lib folder of CXF binary distribution as in CXF 2.2 onwards, CXF is having bouncy castle jar, hence no requirement to download this jar if your CXF distribution already have one.

(or else) Download the latest Bouncy Castle provider (bcprov-jdkXX-xxx.jar) for your JDK, then put it in JAVA_HOME/jre/lib/ext.Edit JAVA_HOME/jre/lib/security/java.security. Find the list of security providers:Add the Bouncy Castle provider to the list as,
security.provider.10=org.bouncycastle.jce.provider.BouncyCastleProvider {assuming 9 entries are there}

Install JCE Unlimited Strength Jurisdiction Policy Files
Due to import control restrictions for some countries, the Java CryptographyExtension (JCE) policy files shipped with the J2SE DevelopmentKit and the J2SE Runtime Environment allow strong but limited cryptography to be used. These files are located at
/lib/security/local_policy.jar
/lib/security/US_export_policy.jar
An unlimited strength version of these files indicating no restrictions on cryptographic strengths is available on the JDK web site for those living in eligible countries.
Unlimited strength Jurisdiction Policy Files may be downloaded from the JavaSoft's web site.Here is the web address:http://java.sun.com/javase/downloads/index.jsp#docs
(At the end of the page under "Other Downloads" section).
Open the readme.txt and follow the instructions:Basically replace two existing jar for the two new ones((US_export_policy.jar and local_policy.jar )

Run your example by passing configuration files we just made

CXF can discover XML configuration files which you have written. For both web service clients and servers, the default location that CXF will look for a configuration for is "/cxf.xml" on the class path.Pass your server and client config files to the Java call to the server and client class as argument
If you wish to override this location, you can specify a command line property: -Dcxf.config.file=some_other_config.xml. This custom configuration file is also expected to be on the class path.
To use a url as the configuration location, specify as follows: -Dcxf.config.file.url=config_file_url
-Dcxf.config.file.url=client.xml
-Dcxf.config.file.url=server.xml

You may get an exception like below:

Caused by: java.io.IOException: exception decrypting data - java.security.Invali dKeyException: Illegal key size at org.bouncycastle.jce.provider.JDKPKCS12KeyStore.cryptData(Unknown Sou rce) at org.bouncycastle.jce.provider.JDKPKCS12KeyStore.engineLoad(Unknown So urce) at java.security.KeyStore.load(KeyStore.java:1185) at org.apache.ws.security.components.crypto.AbstractCrypto.load(Abstract Crypto.java:168) ... 38 more

Don't worry, you just require to put in unlimited strength JCE files in your jdk/jre. Read and follow steps in #Install JCE Unlimited Strength Jurisdiction Policy Files header just above. They will get resolved once you follow steps.

You may get java.security.UnrecoverableKeyException: Cannot recover key - It happens when your storepassword and keypassword are different. Though I think that is a valid case, but as a workaround you can make both passwords the same. Generate the keystores once again, export the certificates and import them into truststore once again. All commands except below two remains the same.

keytool -genkey -alias clientX509v1 -keypass storepassword -storetype jks -storepass storepassword -validity 3650 -keyAlg RSA -keystore client-keystore.jks
keytool -genkey -alias serverX509v1 -keypass storepassword -storetype jks -storepass storepassword -validity 3650 -keyAlg RSA -keystore server-keystore.jks

I hope now you would have seen secured in and out SOAP messages from client and server. :)
Do please let me know if you face some errors, exceptions and also your comments.