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.

19 comments:

jambay said...

Gerard, FYI at least in my resolution / browser, the text gets cutoff for long lines, presumably by CSS or something. I'm using FF3. It looks fine in Google Reader. That's for the post, this is helpful stuff!

Gerard Davison said...

Right,

Second person today to tell me about that. Chris Muir has suggested a solution, will try it later on today.

Gerard

Walker Elliott Rowe said...

Here is a comment for newbies. I could not run wlst as written above so instead I ran it like this after first sourcing the environment with setWLSEnv.cmd:

java weblogic.WLST configWss.py weblogic weblogic localhost 7001 ServerIdentity.jks ServerKey identity ServerKey

Unknown said...

Gerard,

Even after applying the fix that you have suggested, I am still getting the following error.

Client log:
javax.xml.ws.soap.SOAPFaultException: weblogic.xml.crypto.encrypt.api.XMLEncryptionException: Unable to resolve encryption key for weblogic.xml.crypto.encrypt.api.EncryptedType{keyInfo=null, cipherData=CipherValue: Sz49CKJSCJDoF8Wv7LN/KhSoB3uFli/lbQm13BXAsxjbpwKNf3LLE3FW3KUpGUVx9R4T3YWnLON8T8EjPfVgcc255qt1PdADGHTls+ZFuPiewlCeJDKelqwhlXyyjq02EZmlWVIzxgdGsGSzGvIVe/j16ENtuvTr9byxjsrsJ+nVLk/5E/yXjtQMn5fLvgkb5CRutShGbHBONdUaT6O1ML/oFSqIIxevM3wdlc62Nh/jlSrEykbuxC+0eHbPN85t7Gm2N9qrqUeQWRX6DYoakdnO9t8QqePMAVycRacRdGM2gcmvMBgGHPQuMnLOn23ezwbR2OujAuWhFo0kS11bxuE8Y7xgV0GeZ9py1XvE2mW4a45I5RKbGd2evJBAUs7jLSFeB72+7k+/AZlbeZ9Y/2owcdHuLzfsyvFN/I519KwJaKyvIugDkcA9bbtCDjYaLKjg3wTlbseTntHA32dwwUBlCxG0csSp6mmw8BcY1gaB8+fOkaiKqe7II5HdI7I0n5j5GQeTbRWdoVO25o+CuXRBBYhfb6f6LEYhrllDaI4eNPSvsHt7xc4+krpgU2Na5zgqi5er3T2kSsCX6yQV3txGF0wAws7HeTDnxAxBnGM=, id='D2IlSwyBTSOV2NGY', mimeType='text/xml', encoding='UTF-8', encryptionMethod=EncryptionMethod: algorithm = http://www.w3.org/2001/04/xmlenc#aes256-cbc;}

Server Log:
Error BEA-000000 CertPathBuilder does not support building cert path from class weblogic.security.pk.X509ThumbprintSelector
java.security.InvalidAlgorithmParameterException: [Security:090596]The WebLogicCertPathProvider was passed an unsupported CertPathSelector.
at weblogic.security.providers.pk.WebLogicCertPathProviderRuntimeImpl$JDKCertPathBuilder.engineBuild(WebLogicCertPathProviderRuntimeImpl.java:682)
at java.security.cert.CertPathBuilder.build(CertPathBuilder.java:238)
at com.bea.common.security.internal.legacy.service.CertPathBuilderImpl$CertPathBuilderProviderImpl.build(CertPathBuilderImpl.java:67)
at com.bea.common.security.internal.service.CertPathBuilderServiceImpl.build(CertPathBuilderServiceImpl.java:86)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
Truncated. see log file for complete stacktrace
>

What could be wrong?

Sudha.

Gerard Davison said...

Not sure,

It might be you picked up the wrong version of configWss.py. Could you paste a link to the version you are using?

Gerard

kjg said...

Gerard,

I followed your blog, however once I set the system to Sign the request I get the following:

java.rmi.RemoteException: SOAPFaultException - FaultCode [{http://schemas.xmlsoap.or
g/soap/envelope/}Server] FaultString [weblogic.xml.crypto.wss.WSSecurityContext] FaultActor [null] Detail ...xmlns:bea_fau
lt="http://www.bea.com/servers/wls70/webservice/fault/1.0.0"...java.lang.ClassCastException: weblogic.xml.crypto.wss.WSSecurityContext
at weblogic.wsee.security.wssp.handlers.WssHandler.getSecurityContext(WssHandler.java:220)
at weblogic.wsee.security.wssp.handlers.WssHandler.setupSecurityContext(WssHandler.java:189)
at weblogic.wsee.security.wssp.handlers.WssHandler.getSecurityPolicyDriver(WssHandler.java:168)
at weblogic.wsee.security.wssp.handlers.WssClientHandler.processRequest(WssClientHandler.java:65)
at weblogic.wsee.security.wssp.handlers.WssHandler.handleRequest(WssHandler.java:87)
at weblogic.wsee.handler.HandlerIterator.handleRequest(HandlerIterator.java:123)
at weblogic.wsee.handler.HandlerIterator.handleRequest(HandlerIterator.java:99)
at weblogic.wsee.ws.dispatch.client.ClientDispatcher.dispatch(ClientDispatcher.java:101)
at weblogic.wsee.ws.WsStub.invoke(WsStub.java:89)
at weblogic.wsee.jaxrpc.StubImpl._invoke(StubImpl.java:331)
at com.intrado.echo.client.EchoPortType_Stub.echo(EchoPortType_Stub.java:32)
at com.intrado.echoclient.EchoClient.main(EchoClient.java:52)
.../detail>]; nested exception is:
javax.xml.rpc.soap.SOAPFaultException: weblogic.xml.crypto.wss.WSSecurityContext

I'm not sure where I'm going wrong. Does the stack trace tell you anything?

Thanks,
Kevin

Gerard Davison said...

Hmm,

Not sure about your exception I am afraid. Not tried it with RPC, from the stack this appear to be what you are using. Or have I gotten the wrong end of the stick.

Gerard

Kaamos said...

Hi:

I´m new to jdeveloper and weblogic, i was running your example, when i execute the client i always get the following error:

javax.xml.ws.soap.SOAPFaultException: weblogic.xml.crypto.wss.WSSecurityException: Failed to derive subject from token.javax.security.auth.login.FailedLoginException: [Security:090304]Authentication Failed: User Hernan javax.security.auth.login.LoginException: [Security:090300]Identity Assertion Failed: User Hernan does not exist

But when i create user 'Hernan' in weblogic console, execution of code is correct. do you know why it does happen?

Thanks in advance

Gerard Davison said...

Hi,

It is most likely because Herman is the CN you used in your client certificate.

By default weblogic maps this to a username as it is assumed the accepted cert is evidence of identity. I think you configure this under the security realm; but I don't have a wls handy to check at the moment.

Gerard

Josh Bregman said...

Some insight for Sudha

jbruewer said...

Hi Gerard,

i like this blog and i was able to understand the idea. But i've an issue with the user, or the certificate owner? When i test my client, i got also the [Security:090304]Authentication Failed: User HOST-NAME. This means, my "stub" connect with Servername credentials instead of given user? When i create a user in the security reams named as my hostname, it works.... strange ?

regards
Joerg

Gerard Davison said...

Jeorg,

This is due to a change in how the script works in later versions of JDeveloper if you look under you security realm you will see there is a x509 name mapper which takes the CN name of the certificate and enforces this as the user name.

You can either disable this manually, or create the certificate with the correct CName.

Sorry for the late reply,

Gerard

Abhay said...

when i tried executing ur example i get the below error :
#### <[ACTIVE] ExecuteThread: '10' for queue: 'weblogic.kernel.Default (self-tuning)'> <> <> <> <1267877868718>

Unknown said...

After upgraded to new jdeveloper (11.1.1.3.0) the following error is reported.

With previous jdeveloper version everything worked.

Any clue?

javax.xml.ws.soap.SOAPFaultException: Message Expires time has passed
at com.sun.xml.ws.fault.SOAP11Fault.getProtocolException(SOAP11Fault.java:197)
at com.sun.xml.ws.fault.SOAPFaultBuilder.createException(SOAPFaultBuilder.java:130)
at com.sun.xml.ws.client.sei.SyncMethodHandler.invoke(SyncMethodHandler.java:125)
at com.sun.xml.ws.client.sei.SyncMethodHandler.invoke(SyncMethodHandler.java:95)
at com.sun.xml.ws.client.sei.SEIStub.invoke(SEIStub.java:135)
at $Proxy33.fileUpload(Unknown Source)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at weblogic.wsee.jaxws.spi.ClientInstance$ClientInstanceInvocationHandler.invoke(ClientInstance.java:363)
at $Proxy34.fileUpload(Unknown Source)
at aws.client.FTClient.main(FTClient.java:58)
Caused by: javax.xml.ws.soap.SOAPFaultException: Message Expires time has passed
at weblogic.wsee.jaxws.framework.jaxrpc.TubeFactory$JAXRPCTube.processRequest(TubeFactory.java:203)
at weblogic.wsee.jaxws.tubeline.FlowControlTube.processRequest(FlowControlTube.java:99)
at com.sun.xml.ws.api.pipe.Fiber.__doRun(Fiber.java:604)
at com.sun.xml.ws.api.pipe.Fiber._doRun(Fiber.java:563)
at com.sun.xml.ws.api.pipe.Fiber.doRun(Fiber.java:548)
at com.sun.xml.ws.api.pipe.Fiber.runSync(Fiber.java:445)
at com.sun.xml.ws.server.WSEndpointImpl$2.process(WSEndpointImpl.java:275)
at com.sun.xml.ws.transport.http.HttpAdapter$HttpToolkit.handle(HttpAdapter.java:454)
at com.sun.xml.ws.transport.http.HttpAdapter.handle(HttpAdapter.java:250)
at com.sun.xml.ws.transport.http.servlet.ServletAdapter.handle(ServletAdapter.java:140)
at weblogic.wsee.jaxws.HttpServletAdapter$AuthorizedInvoke.run(HttpServletAdapter.java:319)
at weblogic.wsee.jaxws.HttpServletAdapter.post(HttpServletAdapter.java:232)
at weblogic.wsee.jaxws.JAXWSServlet.doPost(JAXWSServlet.java:310)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:727)
at weblogic.wsee.jaxws.JAXWSServlet.service(JAXWSServlet.java:87)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:820)
at weblogic.servlet.internal.StubSecurityHelper$ServletServiceAction.run(StubSecurityHelper.java:227)
at weblogic.servlet.internal.StubSecurityHelper.invokeServlet(StubSecurityHelper.java:125)
at weblogic.servlet.internal.ServletStubImpl.execute(ServletStubImpl.java:292)
at weblogic.servlet.internal.ServletStubImpl.execute(ServletStubImpl.java:175)
at weblogic.servlet.internal.WebAppServletContext$ServletInvocationAction.run(WebAppServletContext.java:3594)
at weblogic.security.acl.internal.AuthenticatedSubject.doAs(AuthenticatedSubject.java:321)
at weblogic.security.service.SecurityManager.runAs(SecurityManager.java:121)
at weblogic.servlet.internal.WebAppServletContext.securedExecute(WebAppServletContext.java:2202)
at weblogic.servlet.internal.WebAppServletContext.execute(WebAppServletContext.java:2108)
at weblogic.servlet.internal.ServletRequestImpl.run(ServletRequestImpl.java:1432)
at weblogic.work.ExecuteThread.execute(ExecuteThread.java:201)
at weblogic.work.ExecuteThread.run(ExecuteThread.java:173)

Gerard Davison said...

gre000ga,

The only think that comes to mind is whether the clock on the client and server is not synchronized properly.

Gerard

mahesh said...

Can I implement the policy below with Jdev 10.1.3 or Jdev 11

http://schemas.xmlsoap.org/ws/2005/07/securitypolicy
Wss11 xmlns:sp="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy

X509 witn basic128RSA15

Mahesh
service@mayoo.com

czetsuya said...

Hi, do you have an idea on how to create a ws client like yours to call the web service in weblogic from jboss/seam?

Gerard Davison said...

Sorry czetsuya, I only know weblogic at the moment.

Sneer said...

Great article! Helped me a lot when securing my web services. Just one question, can you use similar approach to use weblogic configuration when it comes to web service client deployed on weblogic?
My question is can you keep configuration for ClientBSTCredentialProvider on weblogic and not in the code same as you do with ServerBSTCredentialProvider for web service provider. And if you can, how do you achieve that? Weblogic doesn't allow me to have two x509 tokens in one default config...