Skip to main content

Client Side Certificate Handling in Secure Metro WebServices

Posted by kumarjayanti on November 24, 2008 at 5:42 AM PST



If you have a WebService configured to use the href="https://wsit-docs.dev.java.net/releases/m6/WSIT_Security4.html#wp129317">Mutual
Certificates Security  mechanism as supported by
Netbeans.  Then when developing a client for the service you would
generally be required to configure the client side keystore alias or
provide a callbackhandler. And since it is a mutual certificate
scenario you would also have to configure an alias from the truststore
or a callbackhandler to identify the server certificate on the client
side.  Sometimes it may not be practical to expect the 
Certificates to be present inside a  Java Keystore.  
The application invoking the WebService Proxy might obtain it from
other sources (not necessarily a Java Keystore).  With the latest
metro builds starting href="https://metro.dev.java.net/servlets/ProjectDocumentList?folderID=9700&expandFolder=9700&folderID=9003">25th
November  you should be able to set the information as follows
:


cellspacing="2">
 
import
com.sun.xml.wss.XWSSConstants;




....

try { // Call Web Service Operation

test.MyWebService port = service.getMyWebServicePort();

java.lang.String parameter = " This is a Secure Test";



//You may have them available from various sources (including from some
URL)

//For the purpose of this sample i would read them from files.

CertificateFactory fact = CertificateFactory.getInstance("X509");

X509Certificate cert = (X509Certificate)
fact.generateCertificate(new
FileInputStream("D:\\openesb\\client-cert.der"));

PrivateKey key = readPrivateKey("D:\\openesb\\client-key.der");

X509Certificate serverCert = (X509Certificate)
fact.generateCertificate(new
FileInputStream("D:\\openesb\\server-cert.der"));



((BindingProvider)
port).getRequestContext().put(XWSSConstants.CERTIFICATE_PROPERTY, cert);

((BindingProvider)
port).getRequestContext().put(XWSSConstants.PRIVATEKEY_PROPERTY, key);

((BindingProvider)
port).getRequestContext().put(XWSSConstants.SERVER_CERTIFICATE_PROPERTY,
serverCert);

               


java.lang.String result = port.operation(parameter);

out.println("Result = " + result);

} catch (Exception ex) {

// TODO handle custom exceptions here

}



           



As you can see i am reading the certificates and private-key from DER
encoded files.  Here is the non-trivial readPrivateKey() method
that is used above :


cellspacing="2">
/**

 * Private key should be in "DER" format.

 */

public static PrivateKey readPrivateKey(String fileLocation)

throws Exception {



FileInputStream fis = new FileInputStream(fileLocation);

byte input[] = new byte[fis.available()];

fis.read(input, 0, input.length);

PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(input);

KeyFactory key_fac = KeyFactory.getInstance("RSA");

return key_fac.generatePrivate(spec);

}



          



So as you can see we have introduced three properties CERTIFICATE_PROPERTY,
PRIVATEKEY_PROPERTY and 
SERVER_CERTIFICATE_PROPERTY. 
These properties are akin to BindingProvider.USERNAME_PROPERTY
and BindingProvider.PASSWORD_PROPERTY supported in JAXWS specification
for Basic Authentication.  They serve to supply the  Client
Certificate,  Client PrivateKey and Server Certifcate
respectively.  Note that for programmatically specifying username
and password for secure Metro scenarios that href="https://wsit-docs.dev.java.net/releases/m6/WSIT_Security4.html#wp129315">involve
username, we already advocate the use of 
XWSSConstants.USERNAME_PROPERTY
and 
XWSSConstants.PASSWORD_PROPERTY.


The metro client side configuration file wsit-client.xml does
not need to have any Keystore/Truststore configuration in this case.
Infact there is no need for a wsit-client.xml (client side
configuration) in this case and if you are using NetBeans it will not
generate one unless you try to specify any of the Keystore information.



Now you can also get rid of the wsit-client.xml for the first href="http://www.netbeans.org/kb/60/websvc/wsit.html#Exercise_2">NetBeans
secure mechanims href="https://wsit-docs.dev.java.net/releases/m6/WSIT_Security4.html#wp129315">"Username
Authentication with Symmetric Keys
href="https://wsit-docs.dev.java.net/releases/m6/WSIT_Security4.html#wp129315">"
by specifying the following three properties. 



1.  USERNAME_PROPERTY

2.  PASSWORD_PROPERTY

3. SERVER_CERTIFICATE_PROPERTY


cellspacing="2">
try { // Call Web Service
Operation

test.MyWebService port = service.getMyWebServicePort();

java.lang.String parameter = " This is a Secure Test";

               


CertificateFactory fact = CertificateFactory.getInstance("X509");

X509Certificate serverCert = (X509Certificate)
fact.generateCertificate(new
FileInputStream("D:\\openesb\\server-cert.der"));



((BindingProvider)
port).getRequestContext().put(XWSSConstants.USERNAME_PROPERTY, "test");

((BindingProvider)
port).getRequestContext().put(XWSSConstants.PASSWORD_PROPERTY, "test");

((BindingProvider)
port).getRequestContext().put(XWSSConstants.SERVER_CERTIFICATE_PROPERTY,
serverCert);

               


java.lang.String result = port.operation(parameter);

out.println("Result = " + result);

} catch (Exception ex) {

// TODO handle custom exceptions here

}





The  SERVER_CERTIFICATE_PROPERTY is required when using this
mechanism because it is used to secure (encrypt) a Random SecretKey which is
then used to Sign and Encrypt the Request Message from the
Client. 



With all the complexity of WS-* specifications sometimes we get a
feeling that it has become a little hard to do some very simple secure
scenarios.  For example someone just wants to send a simple
username and password (no signature or encryption). Someone just wants
to sign the message payload, or just encrypt the message payload. 
Unfortunately you have to hand edit the  WS-SecurityPolicy
assertions in the WSDL (OR Metro wsit-*.xml, configuration file)
today.  Nebeans defines a predefined set of  Security
Mechanisms which we believe would cover the most common usecases. But
we have always found people wanting to do other things.  One
approach is to pick the closest Netbeans Mechanism and generate the
initial  Metro configuration file and then manipulate the 
Policy assertions to suite your needs.  In the coming weeks i will
try to post
  how one can do some of the very simple
Username/Password, Password Digest, Sign-Only etc. scenarios with
Metro. I shall post the policies of the service for your use.   I
might use the  properties described in this blog for simplicity in
configuring the client.








Comments

client WSDL

Hi man, May be you can help me, I programing a .jar that invoke a WS WSDL with metro 2.0. The invoke must sing with a X.509, I have the files .cer, .key and .key. Do you known how I do that ? thanks! my email is jplistero@gmail.com

Hi Kumar! It would be great! :-D I asked about this possiblility a few months ago: http://forums.java.net/jive/message.jspa?messageID=339230 Please, let me know when it is ready! ;-) Thanks! Ernesto.

yes, you would have to use Metro 2.0 for it. We have also added a new feature recently where the WSDL can publish the server certificate inside the EndpointReference as an Identity element. The client would then never need to configure the peer-alias for encryption since it would automatically get the server certificate. I will post more about it later.

Hi Kumar! The CERTIFICATE_PROPERTY, PRIVATEKEY_PROPERTY, and SERVER_CERTIFICATE_PROPERTY properties don't work in Metro 1.5. Is it normal? Thanks!

Hi Kumar, with "http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702" namespace URI it works fine. Thanks Domenico Loiacono

Also the wst:Claim element should appear inside the X509Token Policy : /sp:X509Token/wst:Claims This optional element identifies the required claims that a security token must contain in order to satisfy the token assertion requirements. see : http://docs.oasis-open.org/ws-sx/ws-securitypolicy/v1.2/ws-securitypolic...

Hi dloiacono , I notice that you are not using the correct version of WS-SecurityPolicy which supports the Claims assertion. AddictionalX509Claim the security policy Namespace URI should be : xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702" but you have given : xmlns:sp="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy"

Hi gekkothelizard , You should be using the latest builds from : https://metro.dev.java.net/servlets/ProjectDocumentList?folderID=9700&ex... Use December 23rd nightly for example.

Are you using Metro 1.4. Let my try the whole scenario and get back to you in a day or two. I will let you know .

I'm trying to do the client side stuff as you suggested with the XWSSConstants, but run into the problem, that when I'm requesting the ws port from the service, I get this exception: Dec 19, 2008 4:04:16 PM com.sun.xml.wss.impl.misc.DefaultCallbackHandler getTrustStore SEVERE: Could not locate TrustStore, check truststore assertion in WSIT configuration Dec 19, 2008 4:04:16 PM com.sun.xml.wss.impl.misc.DefaultSecurityEnvironmentImpl getCertificate SEVERE: WSS0216: An Error occurred using Callback Handler for : EncryptionKeyCallback.AliasX509CertificateRequest Dec 19, 2008 4:04:16 PM com.sun.xml.wss.impl.misc.DefaultSecurityEnvironmentImpl getCertificate SEVERE: WSS0217: An Error occurred using Callback Handler handle() Method. com.sun.xml.wss.impl.XWSSecurityRuntimeException: Could not locate TrustStore, check truststore assertion in WSIT configuration It seems that the system wants to setup the truststore when creating the port, and is not waiting for me to provide the certificate. Isn't there something I must set for this to work?

You could file an issue.

That sounds like a bug.. I will try and fix it soon (this week) then. That's why i wanted to try it out before writing about it. But what you are trying is correct the keystorecallback should have had it. However can you check if the select() method of AliasSelector has the claims info.

Ok, I'm trying to do it, but I have a question:I have to specify a particular callback handler ? If in WSIT client configuration file I define: <sc:KeyStore wspp:visibility="private" aliasSelector="wsit.security.AliasSelector" callbackHandler="wsit.security.KeyStoreCallbackHandler"/> I notice that metaData.getClaims(); in the KeyStoreCallbackHandler return a null element.

Yes this is what i was referring to. Please try it out and let us know if it worked.

Hi Kumar, I'm interested at this solution. I'm using WS-SX and NetBeans 6.5 so I can define in my WSDL a supporting token policy like this: <sp:SignedEndorsingSupportingTokens xmlns:sp="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy"> <wst:Claims Dialect="urn:myDialect">AddictionalX509Claim</wst:Claims> <wsp:Policy> <sp:X509Token sp:IncludeToken="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy/IncludeToken/AlwaysToRecipient" wsp:Optional="true"> <wsp:Policy> <sp:RequireKeyIdentifierReference/> <sp:WssX509V3Token10/> </wsp:Policy> </sp:X509Token> </wsp:Policy> </sp:SignedEndorsingSupportingTokens> And in my Callback handler I can use: CallbackHandler cb = ... Map props = cb.getRuntimeProperties(); com.sun.xml.wss.TokenPolicyMetaData metaData = new com.sun.xml.wss.TokenPolicyMetaData(props); org.w3c.dom.Element claims = metaData.getClaims(); and then verify if Claim contains "AddictionalX509Claim".

hi dloiacono, I would like to restate my answer to your question. If you are using WS-SX version of WS-SecurityPolicy which is supported by NetBeans 6.5 and then you make sure your supporting tokens have the Claims assertions as part of them the there is a way to achieve what you are looking for, We have conciously made the Claims MetaData available to the Callbackhandlers. So you can decide which certificate to use. I can show a sample on how to do this but it will take me some time because i am busy with something else. Let me know if you need this urgently.

Good question!!. We do not support a good way of doing this today. We have been thinking of some possible solution for this. If it is important for you please file a bug so we give it more priority.

How can I set more than one credential for every SupportingToken defined in the security policies for the web service?

Fantastic! In this way is much easier than before! Thanks Kumar! ;)

Sometimes using the certificate with the private key requires a password. Can it be hard-coded similarly to the wss password in your sample? http://webservices20.blogspot.com/ Web Services Security, Interoperability And Testing Blog