Wednesday, January 28, 2009

Deploying JAX-WS RI to Tom Cat

Just some quick notes today on deploying to a JAX-WS RI service to Tomcat. It has to be the RI version as of course Tomcat doesn't have web service support built in. First things first was to edit .../conf/tomcat-users.xml to add a manager account so you can see when deployments go bad. It should look something like this:

<?xml version='1.0' encoding='utf-8'?>
<tomcat-users>
  <role rolename="manager"/>
  <role rolename="standard"/>
  <user username="admin" password="tomcat" roles="standard,manager"/>
</tomcat-users>

You can start tomcat in a variety of ways, I prefer "catalina.sh run" as it doesn't start a process in the background. So it is easier to keep an eye on.

Now if you created your RI class in JDeveloper you might find that the sun-jaxws.xml file is created with incorrect deployment descriptors depending on the build of JDeveloper you are using. Make sure the url-pattern and name match the servlet-name and in web.xml.

<?xml version = '1.0' encoding = 'UTF-8'?>
<endpoints xmlns="http://java.sun.com/xml/ns/jax-ws/ri/runtime" version="2.0">
  <endpoint url-pattern="/Class1Port" implementation="riproject.Class1"
            name="Class1Port"/>
</endpoints>

For comparison the matching web.xml

<?xml version = '1.0' encoding = 'ISO-8859-1'?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5" xmlns="http://java.sun.com/xml/ns/javaee">
    <description>Empty web.xml file for Web Application</description>
    <listener>
        <listener-class>com.sun.xml.ws.transport.http.servlet.WSServletContextListener</listener-class>
    </listener>
    <servlet>
        <servlet-name>Class1Port</servlet-name>
        <servlet-class>com.sun.xml.ws.transport.http.servlet.WSServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>Class1Port</servlet-name>
        <url-pattern>/Class1Port</url-pattern>
    </servlet-mapping>
    ...
</web-app>

When you create a RI web service you do end up with the "JAX-WS RI Web Services" library. This isn't enough to deploy to tomcat, indeed the libraries we are using are modified so they only really make sense when used inside weblogic. Instead you are better of creating a new library from a fresh RI download, make sure you mark as being deployed by default. You could also just add the RI classes to the default classpath for Tomcat, this might make more sense in a production environment.

You can create a connection to your Tomcat instances from the resource pallet in the normal way; but you will find that the web service deployment profile that is created won't allow you to deploy to your new connection.

This is because our profiles default to weblogic as there deployment platform. If you clear this value as in the following screen grab you can then use this deployment profile on tomcat.

If all goes well in deployment you should find that you service is deployed properly, you can monitor this at the default manager URL http://localhost:8080/manager using the password we defined earlier.

Tuesday, January 27, 2009

Code syntax highlighting in blogs

After being promoted by Chris and Jambay I have finally updated my blog to support syntax highlighting to make samples easier to read. I originally followed the steps on this blog but I found that blogger would allow the URL to the .css file. This was fixed by removing most of the query string in the URL for the css:

<link href="http://8296241635750553491-a-1802744773732722657-s-sites.googlegroups.com/site/syntaxhighlightersite/Home/SyntaxHighlighter.css" rel="stylesheet" type="text/css"/>
<script language="javascript" src="http://syntaxhighlighter.googlecode.com/svn-history/r57/trunk/Scripts/shCore.js"/>
<script language="javascript" src="http://syntaxhighlighter.googlecode.com/svn-history/r57/trunk/Scripts/shBrushJava.js"/>
<script language="javascript" src="http://syntaxhighlighter.googlecode.com/svn-history/r57/trunk/Scripts/shBrushXML.js"/>
<script language="javascript">
dp.SyntaxHighlighter.BloggerMode();
dp.SyntaxHighlighter.HighlightAll('code');
</script>

Monday, January 26, 2009

Schema Validation for JAX-WS

We had a very simple test case that confused myself and Alan, the replacement Alan not the old one, for a few minutes today. Our web service looked like this:

@WebService
public class Echo {
    public int echoInt (int i) {
        return i;
    }

}

But when we passed in invalid data to the web service the value of i was 0. So here is example message that JAX-WS will consume properly; but is obviously invalid:

<env:Envelope xmlns:env="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://project1/">
   <env:Header/>
   <env:Body>
      <ns1:echoInt>
         <arg0>xxxx</arg0>
      </ns1:echoInt>
   </env:Body>
</env:Envelope>

It took us a while to remember that schema validation is optional, (See section 1.1 of the JAX-WS specification), and that there is no standard way to turn it on. The RI on the other hand does provide a way and it is as simple as sticking in a annotation. It also has some cool stuff for handling and ignoring specific errors which I find interesting; but I don't have a use case for yet.

import com.sun.xml.ws.developer.SchemaValidation;

@WebService
@SchemaValidation()
public class Echo {
    public int echo (int i) {
        return i;
    }
}

With our previous test data you now get a fault back:

<?xml version = '1.0' encoding = 'UTF-8'?>
<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
   <S:Body>
      <S:Fault xmlns:ns4="http://www.w3.org/2003/05/soap-envelope">
         <faultcode>S:Server</faultcode>
         <faultstring>com.sun.istack.XMLStreamException2: org.xml.sax.SAXParseException: cvc-datatype-valid.1.2.1: 'xxxx' is not a valid value for 'integer'.</faultstring>
         <detail>
            ...
         </detail>
      </S:Fault>
   </S:Body>
</S:Envelope>

Of course there are performance reasons why you might not want to validate the incoming message but it could make your service code much easier if you know it doesn't have to deal with invalid data. Also this is part of the RI so subject to change more than the -WS straight.

WebBeans Renamed -> Java Contexts and Depdency injection

Finally someone has seen sense and renamed the JSR-299 specification to something more general.

It will be good for Java to finally have a standard DI framework, even if it is limited to EE contexts at the start.

Friday, January 23, 2009

Weblogic Documentation Search

I wanted to set up a quick search page to only query the 10.3 weblogic documentation. Google site specific search has to be paid for; but it appears you get it for free if you do adsense so excuse the ads.

Thursday, January 22, 2009

Getting Firefox to use the HTTP Analyzer when run from within JDeveloper

It is really helpful when debugging AJAX application to see the traffic between the the web browser and the client. You can do this using the HTTP Analyzer; but it can get really annoying to have to set and reset your proxy settings in the browser.

It turns out that if you are using firefox you can get around this by using named profiles. The following assumes Linux, but windows people can just clag on .exe to the commands. One thing you have to understand is that by default the firefox command will just open a window on your currently open instance of firefox so you need to use "-no-remote" to create a separately configured instance. So from the command line run:

firefox -no-remote -CreateProfile Debugging

Now just quickly start a firefox with this profile so you can configure the proxy settings to use the analyzer in JDeveloper. (localhost, 8099 and no host exclusions)

firefox -no-remote -P Debugging

So you need to configure JDeveloper to start this special firefox every time, simply go to Tools->Preferences and paste in this command line. It is likely that JDeveloper will complain it cannot verify it and underline it in red; but it does seem to work okay:

So all you have to do is to start the HTTP Analyzer and run HTML/JSP/JSF page from within JDeveloper and a new instance of firefox using the Debugger profile will be started. The downside is that this is less memory efficient as for each run you will be creating a new copy of firefox; but it seems worth it to simplify development.

Annoyingly this trick can't use used directly to configure the java script debugger, due to a bug in the handling of command lines. A work around might be to create a wrapper script for firefox that passed on the above parameters along with any passed values. Don't have time to try that today though.

Wednesday, January 21, 2009

Security Policy Worked Example

Whilst it can be simple in concept many people find configuring security for web services to be something that is very daunting. Unfortunately, and particularly for JAX-WS, there is not yet a nice simple tutorial available that explains all the steps. This isn't that tutorial yet; but I hope to be able to walk through the process providing as much information as possible so as to become a starting point. (Also refer to this weblogic document on the web logic site)

As I work developing tools for weblogic I tend to have a new install every two or three days. For this reason this blog will be from the angle of configuring web logic security from a developers point of view. I will try to annotated the process where you would likely diverge in a production environment. Any commands run in this blog are run in the context of setDomainEnv command that you can find in your domain's "bin" directory. For JDeveloper users who want to configure the integrated domain you will find this in your ~/.jdeveloper/systemXXXXXX/ DefaultDomain/bin directory.

So for the purposes of this blog we are going to consider a simple stock trading application. We are going to pick one of the predefined weblogic policies to make our life easier. My code looks something like this:

@WebService
@Policy(uri = "policy:Wssp1.2-2007-Wss1.1-UsernameToken-Plain-X509-Basic256.xml")
public class BrokerService {

   ...
}

This policy has a bit of everything, user name tokens, encryption of said tokens and then signing of the whole kit and caboodle. A better match for this service in the real world would probably be to encrypt the entire message; but it wouldn't be such a good example so I am going to stick with this policy.

It is worth taking a look at the policy name as the naming convention used by web logic can tell you a lot about what is actually in the file. (For the content of the file take a look at my previous missive) "Wssp1.2-2007" tells you that the policy file contains assertions from the WS-SecurityPolicy 1.2 specification using the revised 2007 name space. "UsernameToken-Plain" tell you that the unecrypted text of the password token if passed in rather than a digest. "x509" for most cases we are talking RSA Public/Private key. Finally "Basic256" tell you which combinations of algorithm suite is being used. The last point takes us to the Wssp1.2 specification section 6.1 which has a table which explains what encryption and what key lengths are required for each suite.

One thing to look at in this document the asynchronous minimum key length, AKL, is 1024 bits this means that you cannot unfortunately make use of the DemoIdentity key store for a simple configuration; but instead need to create some new keys fortunately weblogic has some commands that make this much easier.

Before we get to this we need to take a quick diversion into the topic of trust. For this all to work the server has to be able to trust that the key combination used by the client to sign the message is a valid one. You have two choices for this, either add the client certificate to the server trust store directly or sign the client certificate with a certificate authority that is trusted by the server. The latter is more useful for distributed application as you don't have to worry about out of band key passing so we are going to use it in this example.

Luckily your weblogic instances comes with a demo CA, you can find the certificate and key for this in .../wlserver_10.3 /server/lib/CertGenCA.der and CertGenCAKey.der. This key doesn't appear to change between weblogic installations and is trusted by the default DemoTrust store. For this reason it is very very important you never have the DemoTrust store enabled in a production environment. Otherwise anybody can become trusted fairly easily; but the purposes of setting up a development environment it is really useful.

We are going to use the weblogic CertGen command that will generate keys of the correct key length and more importantly sign it with the demo CA we just mentioned. So we need a client cert/key pair to sign the outgoing message and the server certificate to encrypt the important parts. You are probably bored of me exposing now so lets actually run some commands:

java utils.CertGen -certfile ClientCert -keyfile ClientKey -keyfilepass ClientKey
java utils.CertGen -certfile ServerCert -keyfile ServerKey -keyfilepass ServerKey

The server cert doesn't really need to be signed by the CA; but it is easier to use the same command to save time. Note if you were doing this for a production system you probably want to us something more industrial like openssl to generate your keys as the weblogic documentation recommends. From this you end up with a bunch of .der and .pem files which we need to import into key stores, actually it will create new one for you if they don't exist, to make them easier to use from java, again using the weblogic helper command:

java utils.ImportPrivateKey -certfile ClientCert.der -keyfile ClientKey.der -keyfilepass ClientKey -keystore ClientIdentity.jks -storepass ClientKey -alias identity -keypass ClientKey
java utils.ImportPrivateKey -certfile ServerCert.der -keyfile ServerKey.der -keyfilepass ServerKey -keystore ServerIdentity.jks -storepass ServerKey -alias identity -keypass ServerKey

So now we get into the nitty gritty of configuring the server side of the equation. As mentioned before we are going to rely on the DemoTrust store so we only need to configure the server certificate and private key. Now the easiest way to do this is to make us of a script that comes with the standalone web logic install, for some reason it doesn't get installed with JDeveloper, and you can find the script in ../wlserver_10.3/samples/server/examples/src/ examples/webservices/ wss1.1/configWss.py or from the edocs site. So to configure the server we simply need to run the following command making sure you replace /.../ with the absolute path to the file in each case.

wlst /.../configWss.py weblogic weblogic localhost 7001 /.../ServerIdentity.jks ServerKey identity ServerKey

You can verify that this command has run properly by looking at the "Web Service Security" tab on your domain from the weblogic logic console. Note that the default_ww configuration is used for all web services unless you intimate otherwise. That part of the configuration is for a future blog.

So after restarting your server you can now create a client to invoke this service. The code needs to provide the client key and certificates for signing; the servers certificate so we can encrypt the message and finally something to provide the user name password tokens. For completeness here is the code I used to test this configuration:


import java.security.cert.X509Certificate;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import javax.xml.ws.BindingProvider;
import javax.xml.ws.WebServiceRef;

import weblogic.security.SSL.TrustManager;

import weblogic.wsee.security.bst.ClientBSTCredentialProvider;
import weblogic.wsee.security.unt.ClientUNTCredentialProvider;
import weblogic.wsee.security.util.CertUtils;

import weblogic.xml.crypto.wss.WSSecurityContext;
import weblogic.xml.crypto.wss.provider.CredentialProvider;


//


brokerServiceService = new BrokerServiceService();
BrokerService brokerService =
brokerServiceService.getBrokerServicePort();

// Security stuff
//

// String constants to for server certificate, and client identity store

String serverCertFile = ".../ServerCert.der";
String clientKeyStore = ".../ClientIdentity.jks";
String clientKeyStorePass = "ClientKey";
String clientKeyAlias = "identity";
String clientKeyPass = "ClientKey";

// Create list of credential providers

List credProviders = new ArrayList();

// Create user name token provider

ClientUNTCredentialProvider unt =
 new ClientUNTCredentialProvider("weblogic", "weblogic");
credProviders.add(unt);

// Create a credential provider with the client indentity and the server side
// certificate

final X509Certificate serverCert =
 (X509Certificate)CertUtils.getCertificate(serverCertFile);
serverCert.checkValidity();

CredentialProvider cp =
 new ClientBSTCredentialProvider(clientKeyStore, clientKeyStorePass,
                                 clientKeyAlias, clientKeyPass,
                                 "JKS", serverCert);
credProviders.add(cp);

// Finally add the credential providers to the request context

Map requestContext =
 ((BindingProvider)brokerService).getRequestContext();

requestContext.put(WSSecurityContext.CREDENTIAL_PROVIDER_LIST,
                credProviders);

// Setup the TrustManager to verify the signature on the returned message

requestContext.put(WSSecurityContext.TRUST_MANAGER,
                new TrustManager() {
     public boolean certificateCallback(X509Certificate[] chain,
                                        int validateErr) {
         // Check that the server cert matches
         boolean result = chain[0].equals(
                    serverCert);
         return result;
     }
 });

// Invoke the service

BigDecimal bigDecimal = brokerService.getStockQuote("ORCL");
System.out.println(bigDecimal);

Now of course you need to copy the client keystore and the server certificate to the machine you are running the client from. This is okay as the client keystore with the private key is a secret only the client needs to know and the server certificate is public information.

So here is the general overview of the steps that the weblogic client will go through to send this message:

  • Generate a new aes256 symmetric key, encrypt using the servers certificate. (Think RSA public key) and included in the message
  • Encrypt the WS-Security UNT headers using the aes256 key and replace in message
  • Include the client certificate, which the server trust as has been signed by the demo CA
  • Create signature block with digest for each part of the message and the client private key. (The server can then verify this using the client certificate)

Although this is probably a bit too much detail lets look at an example message that the client could send to the server. I have tried to annotate the message so we can relate it to the configuration we have done do far.

>
<?xml version = '1.0' encoding = 'UTF-8'?>
<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
   <S:Header>
      <wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis 
-200401-wss-wssecurity-secext-1.0.xsd" S:mustUnderstand="1">
      

      
         <ns1:EncryptedKey xmlns:ns1="http://www.w3.org/2001/04/xmlenc#" 
Id="u2KgDzrQ0fxzn776">
            <ns1:EncryptionMethod 
Algorithm="http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p">
               <ns2:DigestMethod xmlns:ns2="http://www.w3.org/2000/09/xmldsig#" 
Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
            </ns1:EncryptionMethod>
            <ns3:KeyInfo xmlns:ns3="http://www.w3.org/2000/09/xmldsig#">
            

            
               <wsse:SecurityTokenReference 
xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" 
xmlns:wsse11="http://docs.oasis-open.org/wss/oasis-wss-wssecurity-secext-1.1.xsd" 
xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" 
wsse11:TokenType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3" 
wsu:Id="str_c8qqMexjG7qPtxHf">
                  <wsse:KeyIdentifier 
EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary" 
ValueType="http://docs.oasis-open.org/wss/oasis-wss-soap-message-security-1.1#ThumbprintSHA1">
+JvAr7erivisYq6D+P8HGAj0678=</wsse:KeyIdentifier>
               </wsse:SecurityTokenReference>
            </ns3:KeyInfo>




            <ns1:CipherData>
               <ns1:CipherValue>rFSQYWTxid4uY6noIglQTy3uPqzhO7/DeVT6apdp2afD5hzw7pgn2HGO
eYyd06gnveW772BEoS0qQqea/kayEmik6ZO0Lme9BjsEiGMOirM8cxp1
GH8ITQEOWX7ZyrruzJq3nbJtECSUGtxsdLh1+YdybfhgXVZ50zE4mGwT
jQc=</ns1:CipherValue>
            </ns1:CipherData>
            

            
            <ns1:ReferenceList>
               <ns1:DataReference URI="#M107teyC8vM4NGla"/>
            </ns1:ReferenceList>
         </ns1:EncryptedKey>
         

         
         <wsse:BinarySecurityToken 
xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" 
xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" 
EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0 #Base64Binary" 
ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3" 
wsu:Id="bst_OICTd53HaizQ97WY">
MIICLTCCAdcCEIaJVGuuAUqDWjfqd+LqWc8wDQYJKoZIhvcNAQEEBQAweTELMAkGA1UEBhMCVVM
xEDAOBgNVBAgTB015U3RhdGUxDzANBgNVBAcTBk15VG93bjEXMBUGA1UEChMOTXlPcmdhbml6YX
Rpb24xGTAXBgNVBAsTEEZPUiBURVNUSU5HIE9OTFkxEzARBgNVBAMTCkNlcnRHZW5DQUIwHhcNM
DkwMTE5MTM0NjU5WhcNMjQwMTIwMTM0NjU5WjB3MQswCQYDVQQGEwJVUzEQMA4GA1UECBYHTXlT
dGF0ZTEPMA0GA1UEBxYGTXlUb3duMRcwFQYDVQQKFg5NeU9yZ2FuaXphdGlvbjEZMBcGA1UECxY
QRk9SIFRFU1RJTkcgT05MWTERMA8GA1UEAxYIdWtwNzkyNjYwgZ8wDQYJKoZIhvcNAQEBBQADgY
0AMIGJAoGBAKSbrv5XD1sjEZxg8LApKmot1T5EqYTEo1J60hwev+3rXZAgjwXaoRx7Z5A2Ln35x
W6CJbhymiV/INfsm93VoJWKoN8g1/cEidoXnNfO+H/6WQPcrTtRuq1X9FrmKYWOAsmkNjX7ohdw
dKtWo+3twNgm+GhPrXi1U830e5PgBVX9AgMBAAEwDQYJKoZIhvcNAQEEBQADQQA/1ucLAAwUE5C
efd7PRk2dPvNX+idsDL+wntiRk2tH5WIxKVKytT64G6wtwLM4q+X2XDBfBHtPkJB1JYFZMyTo
</wsse:BinarySecurityToken>



         <dsig:Signature xmlns:dsig="http://www.w3.org/2000/09/xmldsig#">
            <dsig:SignedInfo>
            

            
               <dsig:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
               <dsig:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
               <dsig:Reference URI="#Timestamp_2aUNpfbuj63zIItu">
                  <dsig:Transforms>
                     <dsig:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
                  </dsig:Transforms>
                  <dsig:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
                  <dsig:DigestValue>FBrjakBhUyh83bJ+qXPavE0HyS4=</dsig:DigestValue>
               </dsig:Reference>
               

               
               <dsig:Reference URI="#Body_1XLlJAczORkplAwo">
                  <dsig:Transforms>
                     <dsig:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
                  </dsig:Transforms>
                  <dsig:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
                  <dsig:DigestValue>FXY8sR0rX7j5AoF/emb89cPI+94=</dsig:DigestValue>
               </dsig:Reference>



               <dsig:Reference URI="#unt_jGt3DAGS0A5sKDXi">
                  <dsig:Transforms>
                     <dsig:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
                  </dsig:Transforms>
                  <dsig:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
                  <dsig:DigestValue>ZvEVCrm9DiSQCEA2lL6TsCGCUZA=</dsig:DigestValue>
               </dsig:Reference>
               
Client certificate signature
               
               <dsig:Reference URI="#bst_OICTd53HaizQ97WY">
                  <dsig:Transforms>
                     <dsig:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
                  </dsig:Transforms>
                  <dsig:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
                  <dsig:DigestValue>s8yt4r8aHbAJ9+MVEd1MkwDy5Dc=</dsig:DigestValue>
               </dsig:Reference>
            </dsig:SignedInfo>
            

            
            <dsig:KeyInfo>
               <wsse:SecurityTokenReference 
xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" 
xmlns:wsse11="http://docs.oasis-open.org/wss/oasis-wss-wssecurity-secext-1.1.xsd" 
xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" 
wsse11:TokenType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile- 1.0#X509v3" 
wsu:Id="str_gm2kU2SAnassqTl7">
                  <wsse:Reference URI="#bst_OICTd53HaizQ97WY"
 ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile- 1.0#X509v3"/>
               </wsse:SecurityTokenReference>
            </dsig:KeyInfo>
         </dsig:Signature>
         

         
         <ns1:EncryptedData 
xmlns:ns1="http://www.w3.org/2001/04/xmlenc#" 
Encoding="UTF-8" Id="M107teyC8vM4NGla" 
MimeType="text/xml" 
Type="http://www.w3.org/2001/04/xmlenc#Element">
         

         
            <ns1:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#aes256-cbc"/>
            <ns1:CipherData>
               <ns1:CipherValue>
oUoMOMf12IAMEgZ01UuaHY+xYlKkYeaAIrZyuN5CEafQRco1HecGmaGcjtB5q
cNrRTNmrE9S18Z9K1oE6kwHKp3ZeYMp7KF/TbiqOwvKsy/+YpTQMS8gaqgbDN
XlRi0gG5/CZO6yqParDs//h3xvC9L1uazotzTGJofDWXaF/O8RC0qamD6yuoH
olV38na2mq28X0j44Eki4zJIkQg9q2ORj1juEE8RBt/zNuFKggThJrsmsixUj
AVRHXYA0exbwqUgWGoEEvw/AK4ZQooXfBXfIOsvPn4O4e515QpXhtM6cuqUEM
soGSIO/N+HT8oi4tOurXOAVCMZw6RonqBRvUPvLl2MQm3RIg4kBNFN7VIkqw4c
3jj+BbjGksKrmT3XX9jgypDDKJbW0OcOCTGYMhawQ2/wJMH/JazR55zwRLEzn8
8EIrLQ4SuGU7TN3pRNXdL3GdRxMZXF05mPT+6FLiSZ73kQLXxjlfQ9Bx4U3k2W
m+Pa0nMk0vb8Vj2DV5ZOB830f9C15jCIn7cvFZmYIdXSLOl1zrBJ1zGpdmVov
e1eKETKOyADGhWfE4Rt7mxPhLsUrhOlLIg4YMp+q3MIFEknoB8aBS0JPs9TSPvkQ2tk=
</ns1:CipherValue>
            </ns1:CipherData>
         </ns1:EncryptedData>
         <wsu:Timestamp 
xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" 
wsu:Id="Timestamp_2aUNpfbuj63zIItu">
            <wsu:Created>2009-01-20T14:35:09Z</wsu:Created>
            <wsu:Expires>2009-01-20T14:36:09Z</wsu:Expires>
         </wsu:Timestamp>
      </wsse:Security>
   </S:Header>



   <S:Body 
xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" 
wsu:Id="Body_1XLlJAczORkplAwo">
      <ns2:getStockQuote xmlns:ns2="http://webservice.stockbroker.com/">
         <ticker>ORCL</ticker>
      </ns2:getStockQuote>
   </S:Body>
</S:Envelope>

I will leave the analysis of the response message from the server as an exercise for the reader at this point; but I think you get the general idea of how the different parts of the configuration to hang together to create a message.

It is worth trying, as a sanity check, using a client key that is not trusted by the server. You can easily create such a key using the keytool command

keytool -genkey -keyalg RSA -keystore UnsignedClient.jks -storepass ClientKey -alias identity -keypass ClientKey -dname "CN=Client, OU=WEB_AGE, C=UK" -keysize 1024 -validity 1460

In this case when the client is run with the new keystore the server will response with an indignant response that the certificate could be verified. The stack trace you might see will look something like this the following, this could be fixed by adding the new client certificate to the server key store we configured earlier.

Exception in thread "main" javax.xml.ws.soap.SOAPFaultException: Security token failed
 to validate. weblogic.xml.crypto.wss.SecurityTokenValidateResult@137c90d[status: false]
[msg [
[
  Version: V3
  Subject: CN=Client, OU=WEB_AGE, C=UK
  Signature Algorithm: SHA1withRSA, OID = 1.2.840.113549.1.1.5

  Key:  Sun RSA public key, 1024 bits
  modulus: 10367272402852596114462785541689739976823783564655877706471495047404251812...
  public exponent: 65537
  Validity: [From: Tue Jan 20 16:18:56 GMT 2009,
               To: Sat Jan 19 16:18:56 GMT 2013]
  Issuer: CN=Client, OU=WEB_AGE, C=UK
  SerialNumber: [    4975f970]

]
  Algorithm: [SHA1withRSA]
  Signature:
0000: 65 F7 E6 13 7F 47 50 20   F5 DA 01 BE 44 39 B1 5E  e....GP ....D9.^
0010: 0E A3 23 CD 39 95 BB 3E   D2 CD 1E B8 A2 3E FC 74  ..#.9..>.....>.t
0020: F3 06 78 3C 2D 43 D8 26   E9 A3 2F 24 3F C2 A2 FF  ..x<-C.&../$?...
0030: 10 2D E1 ED 09 34 7F E8   B8 48 04 38 DE 4E B3 D9  .-...4...H.8.N..
0040: 37 27 F1 42 74 C1 A9 0C   61 E7 23 7F 09 A1 2F F1  7'.Bt...a.#.../.
0050: EC 0B 10 40 F8 DD C1 39   62 92 0A 62 96 D2 F8 5F  ...@...9b..b..._
0060: EF AF E3 93 C4 3E 62 D7   2F 5A 78 65 54 BD 28 4B  .....>b./ZxeT.(K
0070: DF 34 55 7D 8C 10 05 5A   DB 91 D8 A0 46 65 C3 16  .4U....Z....Fe..

]]
 at com.sun.xml.ws.fault.SOAP11Fault.getProtocolException(SOAP11Fault.java:190)
 at com.sun.xml.ws.fault.SOAPFaultBuilder.createException(SOAPFaultBuilder.java:122)
 at com.sun.xml.ws.client.sei.SyncMethodHandler.invoke(SyncMethodHandler.java:119)
 at com.sun.xml.ws.client.sei.SyncMethodHandler.invoke(SyncMethodHandler.java:89)
 at com.sun.xml.ws.client.sei.SEIStub.invoke(SEIStub.java:118)
 at $Proxy30.getStockQuote(Unknown Source)
 at com.stockbroker.webservice.BrokerServicePortClient.main(BrokerServicePortClient.java:107)
Process exited with exit code 1.

So this blog should have shown you have to understand policy names, attach policy to a class, configure a server with the correct key stores, create a client and some understanding on how the bit relate to the structures you will find in the resultant soap message. As I say before this is not a definitive tutorial; but perhaps at least a starting point for a further investigation.

Update 11 February: If you have been using this example to try to perform two way encryption you you will find that the client will fail to decrypt the message. This is because of a mistake in my original code, it has a trust manager that only trusts the server certificate:

// Setup the TrustManager to verify the signature on the returned message

requestContext.put(WSSecurityContext.TRUST_MANAGER,
                new TrustManager() {
     public boolean certificateCallback(X509Certificate[] chain,
                                        int validateErr) {
         // Check that the server cert matches
         boolean result = chain[0].equals(
                    serverCert);
         return result;
     }
 });

The failure message from weblogic wasn't particularly useful so I spend a lot of time making sure that the keys in the messages lined up.

Exception in thread "main" javax.xml.ws.soap.SOAPFaultException: weblogic.xml.dom.marshal.MarshalException: weblogic.xml.crypto.wss.WSSecurityException: weblogic.xml.crypto.encrypt.api.XMLEncryptionException: Unable to resolve encryption key for weblogic.xml.crypto.encrypt.api.EncryptedType{keyInfo=null, cipherData=CipherValue: 0i8YETKYNv6PKD9nZqikDDIYpBrqrfDORnLK+nyJiY9HBaE462+v/PCG0NCbO4kqyotFGPqMExSCZ4hYOGtR4nWseqoAWD7Z64SPKfNYv0ugRhTcGIsJ8kya1eJFOzNfwRFPSaalRzLDQ8j+Rl7yiw==, id='null', mimeType='null', encoding='null', encryptionMethod=EncryptionMethod: algorithm = http://www.w3.org/2001/04/xmlenc#aes256-cbc;} 

The fix for this was to replace the trust manager with one that either trusts everything, and returns true, or checks the client certificate. It is better to got for the latter.

List certificate = CertUtils.getCertificate(clientKeyStore,
  clientKeyStorePass,
  clientKeyAlias, "JKS");

final X509Certificate clientCert =
  (X509Certificate)certificate.get(0);


...

// Setup the TrustManager to verify the signature on the returned message

requestContext.put(WSSecurityContext.TRUST_MANAGER,
                new TrustManager() {
     public boolean certificateCallback(X509Certificate[] chain,
                                        int validateErr) {
         // Check that the server cert matches
         boolean result = chain[0].equals(
                    serverCert) || chain[0].equals(clientCert);
         return result;
     }
 });

I did think about fixing the code in the blog and saying no more about it, but I feel that you can learn more from people's mistakes as well as they successes. Thanks for Chris Muir for working through this one with me.

Food at Oracle, Reading, UK

On of the nice things about working for Oracle at the Reading office is the quality of the restaurants, today's lunch was so pretty I just couldn't help posting a picture of it.

Monday, January 19, 2009

Viewing the Contents of WLS Policies in JDeveloper

If you want to know what is behind each WLS policy then in JDeveloper the simplest bet is to deploy your application. If you want to have a quick read before you decide which one to use you can convince the application navigator to display all the policies. you simply need to check "Show Libraries" in the application navigator and go to the relevant package.....

You can then open the policy file you are interested in like you would any other...

Friday, January 16, 2009

Weblogic Server 10.3 documentation as PDFs

Just a quick like to the web logic documentation in PDF format I find them much easier to work with as a lot of seperate pages are joined into one big document. They are also easier to print out and write on, although as the web service security one is 150 odds pages long you might not want to do this for the sake of the trees.

Tuesday, January 6, 2009

Quick start using Jersery Maven Architype

Just a real quick way to set up your environment for playing with Jersey, taken from this sun blog. Simply run the command:

mvn archetype:generate -DarchetypeCatalog=http://download.java.net/maven/2

Now you can just use this with as a JDeveloper project or run the war:war command for a nice bundled list of dependencies for use elsewhere.

Monday, January 5, 2009

Some nice RESTful articles from InfoQ and Others

Just getting back into the swing of things and ended up with a nice long tab group of links. Figured I would write them down as they represent quite a nice introduction of the key concepts.