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.