Skip to main content

Security Token Configuration in Metro

Posted by kumarjayanti on June 1, 2009 at 4:45 AM PDT

In this post, i  would like to describe how to configure various types of security tokens that Metro supports. There are various aspects to token configuration depending on the type of the token and the article i wrote long ago is outdated, things have changed for good and i will talk about it here.

The details in this entry would be applicable to Metro 2.0 EA (to be released for JavaOne 2009) and Metro 2.0 Final Release. I would not be at JavaOne 2009 but the Metro Architect Harold and Jiandong (Lead for WebServices Trust and SecureConversation implementation in Metro) would present a Technical Session : Metro Web Services Security Usage Scenarios on Thursday, June 04, 9:30 AM - 10:30 AM Hall E 134. So if you are attending JavaOne 2009 do plan to go for the session.

The WS-SecurityPolicy specification defines a whole set of token assertions that can be used for securing SOAP messages. Metro supports some of them. The token assertions are abstract declarations of the type of token to be used and can contain other information such as claims, reference types etc. The abstract token assertions need to be bound to concrete physical tokens from the runtime environment for Metro to be able to secure the messages. The notation for establishing this binding is not defined in any specification and hence each vendor implementation would have its own proprietary way of doing this. In this blog i would describe how the binding is done in Metro.  The binding in metro is essentially expressed in terms of  proprietary token configuration assertions inside the Metro client and server side configuration files. More details about writing metro client and server side configuration files can be found here.   Metro attempts to move this binding to a standard API JSR 196 CallbackHandler and Callbacks defined by the JSR (in other words the entire configuration for various tokens can be achieved by implementing a single CallbackHandler and configuring the CallbackHandler in the client and server side metro configuration files). However the result is not a totally clean binding (devoid to proprietary stuff). This is because JSR 196 defines a minimal set of necessary callbacks but we endup requiring other types of callbacks when handling WS-Security. To this effect the JSR 196 specification does allow the Callback Handler to handle other types of callbacks where necessary.

Note that there is support in NetBeans for most (if not all) of the configurations described in this post.  This post is very informal and is a prelude to Documentation that would eventuall appear. However it contains the set of all configurations (some of which were probably not publicly documented before).

Underlying Architecture for Token Configuration

 Before describing the token configuration details it would help if i describe how the metro security runtime tries to obtain the configuration. As metro security involved from early days in 2004 we realized two things :

1. The use of the JAAS CallbackHandler for obtaining Tokens especially username/password is a standard approach in Java.

2. Metro has to run in different enviroments/containers and there could be different set of Callback Vocabularies in different environments. For example Pre-Metro XWSS defined its own set of  Callbacks and JSR 196 defines another set of standard Callback subset in the javax package.

 So it was clear that Metro Security runtime cannot depend on any specific set of Callback's if it were to run on different environments, but instead should utilize the callback vocabulary of the target container on which it is running. Accordingly the Metro Security runtime defines an Internal SPI called SecurityEnvironment which has necessary methods for retrieving Tokens of various types, possibly using some search criteria (for example locate a certificate which has a given IssuerName and IssuerSerial value). Then there are different default implementations of this SPI within metro and the right implementation is picked up based on the environment. The SPI implementation would then invoke the container/environment specific callbackhandler. So one can expect that the configuration required by metro would be influenced to some extent by the configuration needed by the underlying CallbackHandler used by the container (although the general design goal is to make the configuration agnostic to the underlying CallbackHandler of the target container).

In this post you would see the use of term CallbackHandler and Validator at several places and the way these pieces fit together is that metro has two default implementation's of the SecurityEnvironment SPI,  one implementation used for all  Non-GlassFish containers and also for GlassFish Non-109 deployments and another implementation of the SPI for GlassFish 109 deployments.  This is because 109 deployments on GlassFish can levarage the Default JSR 196 CallbackHandler implemented by GlassFish. Using a native CallbackHandler supported by the container results in less configuration required in the Metro configuration file(s), although it may put some external (container specific) configuration requirements.

So the first implementation of the SPI invokes  a Metro DefaultCallbackHandler (which operates on the Metro/XWSS specific Callback vocabulary) and the second implementation invokes the JSR 196 CallbackHandler of GlassFish. So the DefaultCallbackHandler in the first case is a Gigantic Wrapper which would inturn delegate to any CallbackHandler(s) and Validator(s) specified in by the developer in the Metro configuration files.  In the  second case it turns out that the JSR 196 Callback vocabular is actually a subset of what would be required in a WS-Security environment and hence the SecurityEnviroment SPI uses a Mixed approach.  If a JSR 196 Callback exists for a particular case it would  invoke the JSR 196 CallbackHandler by default unless overriden by a metro specific configuration. If a JSR 196 Callback does not exist (or was overriden) for a task then it would directly invoke any CallbackHandler(s) and Validator(s) specified by the developer in the Metro configuration.

 Note: It is possible for GlassFish Non-109 (plain-jaxws) webservice deployments to make use of the JSR 196 dependent SecurityEnvironment SPI implementation. This can be achieved by placing the jar gf-196-hook.jar in the lib directory of GlassFish and re-starting GlassFish.

  Metro Security supports the following token assertions defined in the WS-SecurityPolicy specfication :

  • Timestamp Token
  • Username Token
  • X509Token
  • SAML Token
  • Kerberos Token
  • Issued Token 
  • SecureConversation Token

The last one is not an authentication token but metro allows certain configuration for it and hence i have mentioned it there.  

Let us look at the token configuration details for various tokens supported by Metro. We would also refer to them as Configuration Assertions in this post since they are really proprietary assertion's using the same WS-Policy syntax. One might wonder if it could cause some interoperability problems but the fact of matter is that these assertions are required to bind the various aspects of the  Token Assertions to phyiscal entities, and these assertions are marked with Visibility attribute private stating that the other party importing the WSDL would not see these assertion.  

Token Configuration for the Timestamp Token

 

The timestamp token can appear in both request and response messages and hence the configuration described here applies to both the client and server side with the exception that the namespace of the configuration would be http://schemas.sun.com/2006/03/wss/server on the server side and http://schemas.sun.com/2006/03/wss/client on the client side, However different configurations apply to an outgoing timestamp and an incoming timestamp.  .  

Note that this namespace distinction described here applies to all configuration assertions that can appear on both the client and server side and i may not emphasize this again in this post.

Outgoing Timestamp Configuration

 

For an outgoing timestamp the Expires time as shown in the sample timestamp token  (timeout interval) can be controlled.

         <wsu:Timestamp wsu:Id="3">
            <wsu:Created>2009-05-30T06:14:45Z</wsu:Created>
            <wsu:Expires>2009-05-30T06:19:45Z</wsu:Expires>
         </wsu:Timestamp>

So the required configuration is an attribute timestampTimeout on the CallbackHandlerConfiguration. This can appear on both the client and server side with appropriate namesapce.

<sc:CallbackHandlerConfiguration
        timestampTimeout="{Timeout value in Second(s) : This value is used to compute the Expiry time of the WSU:Timestamp being sent in the message,

value specified should be greater than zero}"/>

 

 

 The default value for timestampTimeout is 5 seconds.

Configuration for an Incoming Timestamp

 

 And incoming Timestamp needs to be validated and the set of configuration to control this validation process is described in the following post. The configuration described in the post are about configuring the default timestamp validation process in Metro. However one can optionally take the complete timestamp validation into their own hands by configuring a TimestampValidator assertion under the ValidatorConfiguration. See the abstract schema below.

    should implement com.sun.xml.wss.impl.callback.TimestampValidationCallback.TimestampValidator,
    a default Timestamp validator from XWSS runtime is used when not supplied} />

The attributes described in the post would then have no effect when someone configures a Validator for timestamps.

Note: In this post i am showing the  child assertions of  CallbackHandlerConfiguration and ValidatorConfiguration in a token wise manner showing only the relevant portions each time. In reality there can only be a single CallbackHandlerConfiguration and a single ValidatorConfiguration with all child assertions combined under them. The runtime currently does not validate this restriction, users need to be aware of it. Also note that Metro currently does not perform schema validation for any of the configuration(s) described in this post.

 Token Configuration for UsernameToken

 

 This section describes the client and server side configuration possibilities for dealing with UsernameToken assertions.

 Client Side Configuration for UsernameToken

 

  The primary action on the client side for a UsernameToken is to specify the username and password. There can be three different types of clients  webservice clients and we shall discuss the configuration applicable to each of them. The three possible types of clients are

  1.  Standalone Java Clients
  2. WebApplications/WebServices acting as client to another WebService 
  3. Java EE Application Clients
Standalone Java Clients

 The configuration possible for Standalone Java Client's is two fold

  1. Programmatic Username and Password supplied as properties on the BindingProvider.RequestContext. This kind of configuration is shown  in my earlier post here.
  2. described in the following abstract schema

  useXWSSCallbacks="{Value true indicates use XWSS Callbacks in place of Standard J2SE callbacks for Non-109 App. For 109 Apps a value true indicates passing RuntimePropertiesCallback as an Extra Callback to CallbackHandler.handle(Callbacks[]) method}" >
               default="{the default username value as a string, to be provided incase classname is not provided}"/>
               default="{the default password value as a string, to be provided incase classname is not provided}" />


 So one can either specify a default username and password

 

xmlns:sc="http://schemas.sun.com/2006/03/wss/client" >
      
      

 

or specify a Username and Password Handler separately as below

xmlns:sc="http://schemas.sun.com/2006/03/wss/client" >
      
      

The first option is generally for quick and dirty development. The attribute useXWSSCallbacks is relevant in the second case. By default the UsernameCallbackHandler is expected to handle NameCallback  and PasswordCallback defined in the javax package but by specifying useXWSSCallbacks="true" metro would expect the Handler to handle UsernameCallback and PasswordCallback from com.sun.xml.wss.impl.callback  package, the support for useXWSSCallback attribute was added based on request from metro forum users, and the reason is  a unique property of  the callbacks defined in com.sun.xml.wss.impl.callback  package. The callbacks in this package extend XWSSCallback (base class) which supports a public method   public HashMap getRuntimeProperties(); ks these are properties defined by JAXWS runtime as well as  properties that developers can set inside the client program on the BindingProvider's RequestContext.  An example of how the Metro user made use of these runtime properties is as follows :

 The user would have a WebServiceClient that needs to contact multiple WebServices and the username/password pair for each service is different. So the developer could use a single CallbackHandler implementation but then set some property within the client (BindingProvider.RequestContext) indicating the Service being called. The CallbackHandler would then get this property as a runtime property on the callback and can return the username/password appropriate for the service being invoked.

As you can see this would not be possible if the Callback used was a standard javax NameCallback/PasswordCallback  since it does not allow setting any properties on it.Another more relevant example would be the case when the WS-SecurityPolicy of the service has more than one Token of the same type. Let's say one as a Binding Token and another as a Supporting Token or an Endorsing Token. Please read the WS-SecurityPolicy specification for more details on what are supporting and Endorsing Tokens.  But the thing to understand here is that a callback handler needs to return a different token for the  Binding  and Supporting/Endorsing Tokens case.  So unless the Callback Handler has some information conveyed through the Callback about the type of usage of the token (Binding/Endorsing/Supporting) there is no way it can return the right token. Please note that this particular description applies to any security token supported by Metro and not just username/password.  So it turns out that it is difficult for runtime to convey this information directly to the callback. But the latest versions of WS-SecurityPolicy specification comes to the rescue.  A Token assertion can have the following child metadata assertions :

  1. Token Issuer
  2. Required Claims

This metadata can now be accessed by the callbackhandler using the TokenPolicyMetaData API (see sample code below). This API again makes use of Runtime Properties on the callback under the covers.

import com.sun.xml.wss.impl.callback.XWSSCallback;
import java.io.IOException;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.UnsupportedCallbackException;

public class MyCallbackHandler implements CallbackHandler {

    public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
        for (int i = 0; i < callbacks.length; i++) {
            if (callbacks[i] instanceof XWSSCallback) {
                XWSSCallback cb = (XWSSCallback)callbacks[i];
                com.sun.xml.wss.TokenPolicyMetaData data = new com.sun.xml.wss.TokenPolicyMetaData(cb.getRuntimeProperties());
                org.w3c.dom.Element claims = data.getClaims();
                String issuer = data.getIssuer();
                ....
                //rest of CBH processing
                if (issuer.equals("XYZ")) {
                    //do something special
                } else {
                    //do something else
                }
            }
        }
    }

WebApplications/WebServices acting as Clients to another WebService

 

WebApplication and WebService clients have the following configuration options

 

  1. Programmatic Username and Password supplied as properties on the BindingProvider.RequestContext. This kind of configuration is shown  in my earlier post here.
  2. CallbackHandler configuration (described for standalone clients above) but only the default static option. This is because there can be no Callback from a WebApplication back to the End-User.

xmlns:sc="http://schemas.sun.com/2006/03/wss/client" >
      
      

But as noted earlier this option has the drawback of storing the plain-text password inside a configuration file. Metro security users on GlassFish have an option here. They can leverage the password security feature by creating a password  alias  and storing the actual password in an encrypted password store.  The only requirement here is that the password alias should start with a "$" symbol, for example, below is the configuration of user "xyz" with password alias "$xyzpasswordalias".

 

xmlns:sc="http://schemas.sun.com/2006/03/wss/client" >
      
      

The metro runtime knows to contact the password store when it sees that the password specified in the configuration begins with a "$".

 

JavaEE Application Clients

 

JavaEE Application Clients have the following options

  1. Programmatic Username and Password supplied as properties on the BindingProvider.RequestContext (same as with other types of clients above)
  2. Use the GlassFish Default AppClient CallbackHandler for collecting the Username/Password
  3. Specify a Custom CallbackHandler configured with the GlassFish Appclient Container.

Server Side Configuration for UsernameToken

The primary action(s) on the server side for a UsernameToken are two fold

  1. Validation of the Username-Password pair and setting the corresponding caller principal which can be used for authorization purposes
  2. Controlling the time-period for which a recieved Nonce is  stored on the server for replay detection

There are three different validation scenarios depending on the Type/Usage of the UsernameToken in the Policy of the Service.

  1. Username Token containing Plain-Text password and username being used as an Authentication Token. Usually configured as a *SupportingTokens in Policy. The wildcard before the SupportingTokens keyword is because the WS-SecurityPolicy  specification allows specifying an Encrypted/Signed/SignedEncrypted SupportingToken. 
  2. Username Token containing the hashed password (also known as Password Digest Authentication).
  3. Username Token used as a Binding/Endorsing Token where the token password is used to derive a new symmetric key which is used for Signing and Encrypting the Messages. This is also referred to as password derived keys as described in OASIS WS-Security UsernameToken Profile 1.1 specification.
Configuration for Plain-Text Username/Password Validation

 

For a plain-text username/password  most containers define some mechanisms for validating the pair. Java EE as such does define any API for defining the same and hence each container would have its own proprietary framework and API's. So there are two different deployment scenarios for which different mechanism apply. The four scenarios are

  1. GlassFish 109 deployment
  2. Non-GlassFish container or GlassFish Non-109 deployment

For GlassFish 109 deployments there is no configuration required for Plain-Text Username-Password  validation within the Metro configuration files. Instead one would need to configure the GlassFish Realm for the application and make sure the appropriate users exist in the Realm being configured. More details on this can be found here. As noted earlier GlassFish 109 deployments make use of the underlying GlassFish JSR 196 CallbackHandler and i have also described how a GlassFish Non-109 deployment can also be forced to make use of the JSR 196 CallbackHandler.

For Non-GlassFish containers and for GlassFish Non-109 deployments the following two options exist

  1. ValidatorConfiguration can be used  for validating passwords. The override rule defined earlier applies as well, i.e one can configure a Validator for a 109 deployment and it will override the default JSR 196 callback.
  2. A RealmAuthentication Adapter can be specified.

A ValidatorConfiguration with a usernameValidator child on the server side WSDL has the following abstract schema.

    should implement com.sun.xml.wss.impl.callback.PasswordValidationCallback.PasswordValidator  a sample validator can be seen here}/>

 As noted earlier i am showing pieces under ValidatorConfiguration as applicable, there can be other types of validators under the ValidatorConfiguration that will be shown elsewhere in this post. There has to be a single ValidatorConfiguration element on the client/server side.  Since we are talking about Plain-Text password validation here, so the validator is expected to recieve a PlainTextPasswordRequestObject here.

As it turns out the validate method on the Validator : boolean validate(Request request) throws PasswordValidationException;  is a legacy method and does not provide a way for the validator to set the caller-principal somewhere such that the target container can then interpret it, in this case metro sets the caller-principal in a container independent manner.

  The second option was designed based on the idea that most containers have a notion of  Realms which allow authentication against them. So for RealmAuthentication on Containers other than GlassFish we have this SPI called com.sun.xml.wss.RealmAuthenticationAdapter.

It has an abstract method :

public abstract boolean authenticate(Subject callerSubject, String username, String password) throws XWSSecurityException;

So what does the developer need to do :

1. Implement your own RealmAuthentication class that extends the com.sun.xml.wss.RealmAuthenticationAdapter.
2. Package the implementation class inside your WAR File
3. Create a META-INF/services entry (inside the WAR) for your RealmAuthenticator. The services file should be named as : com.sun.xml.xwss.RealmAuthenticator and the contents of the file should be the fully qualified package name of your RealmAuthenticator class.

This allows for an application specific configuration of RealmAuthenticator.  Since the clientSubject is passed as an argument, the Autheticator could also update the Subject with the target containers representation of the Caller Principal.

Server Side Configuration for Password Digest Authentication

 

 The configuration required for Password Digest authentication is again a usernameValidator. And this applies to both GlassFish 109 deployments and Non-GlassFish deployments. The details of the configuration are described here. GlassFish Realm SPI's allow for developing custom realms that support Digest Authentication, in addition the JDBC Realm in GlassFish V2.1 and GlassFish V3 does support Digest Authentication. So, ideally no configuration should be required for Password Digest Authentication  in metro when running on GlassFish V2.1 and V3, however this particular integration of Metro with Digest Authentication in Realms is a TBD for future releases of metro.

Another piece of configuration relevant to Password Digest Authentication is a parameter that controls the Caching of Nonce values present in the UsernameToken. A Nonce is especially a mandatory element in Password Digest authentication, see the WSS 1.1 UsernameToken profile for a description of the Nonce element. So the Metro implementation would cache Nonces and can detect a message replay based on a repeated Nonce value. However it is obivious that a received nonce cannot be stored indefinitely on the server (it would result in a memory leak, and can be the cause of a DOS attack). So the specification recommends that nonces be stored for a configurable time-period. Accordingly the following attribute on ValidationConfiguration can be specified by application developers :

sc:maxNonceAge="{The length of time (milliseconds) a previously received Nonce value in a
UsernameToken will be stored, runtime default of 15 minutes used when not specified}"?

>
Note that this attribute is one among many other attributes allowed on a ValidatorConfiguration. The other attributes are defined elsewhere in this post. The NonceCache used by Metro is a global Nonce Cache and hence Nonces have to be unique across applications. And so one can imagine that if multiple WebServices were deployed with different values for this attribute, then only the value defined by the first deployed WebService will be used in reality as the maximum Nonce Age. This is a minor ceveat that developers need to be aware of.

 

Server Side Configuration for Password Derived Keys

 

Password Derived Keys is an interesting new addition to Metro 2.0. It allows a username-password to be used for authentication as well as integrity/confidentiality protection. The configuration required for this case is again a usernameValidator for both  GlassFish 109 and Non-GlassFish deployments.  The details can be seen here. Again here it is possible to have support for this with No configuration whatsoever when running on GlassFish, but this integration with GlassFish has not happened yet and is a TBD for future

Configuration for X509Token

 

The X509 Token is the most commonly used token with metro and we have a whole lot of configuration syntax around it. When talking about X509Tokens that thing that comes to our mind immediately is the Java Keystore API and it would appear that the only way to configure X509Tokens with Metro is to use a KeyStore. But this is not true, as described in the beginning, the Metro SecurityEnvironment (Internal) SPI deals only with Keys and Certificates and has no dependence on the Java Keystore. The idea is that the keys can come potentially from anywhere, even a plain file on the filesystem,  but handling such cases would require custom code to be written by the developers. I shall say more  about it towards the end of this post.

However the DefaultCallbackHandler in Metro (which is used when running metro on GlassFish with Non-109 deployments or when running Metro on Non-GlassFish containers ) needs to be configured with  Keystore(s), Truststore(s) and Certstore(s) to be able to do its job. The following configurations are possibile for X509 Tokens.

A KeyStore is used to store the keys-pairs (certificate and private-key) of the entity participating in a WebService interaction. A TrustStore is used to store trusted CA certificates. A CertStore is used to store trusted other-party certificates. In general KeyStore, TrustStore and CertStore(s) would need to configured on both the client and server side (with appropriate namespace change). In addition one may configure a Certificate Validator for Validating incoming certificates (this is generally done on the server side).

Note : Though most of the samples and NetBeans UI today allow configuring other-party (non-CA) certificates inside truststore this is not a good idea in reality, though it allows quick and dirty development. This is because the truststore is meant to contain only CA certificates or trust-roots. Metro supports a CertStore configuration that can be used to store other-party certificates. We have not demonstrated samples around it but some metro users have used it. We intend to support the SSL/TLS Handshake and SPNego protocols (at the SOAP Layer) for WebServices in future Metro releases. This will reduce the need to store other-party (non-CA) certificates in general.There is also a Programmatic way of configuring a single private-key and certificate pair on the client side (it will not help if the policy requires multiple X509 Tokens for securing the message such as one for binding and another for endorsing). This is desribed in my earlier post.

 Static Configuration of KeyStore

     location={absolute path to keystore file OR a path relative to META-INF (on the classpath), not required for 109 cases}?
   type={type of the keystore (default is JKS)}?
   storepass={the password of the keystore as a string, OR a fully qualified classname of a class implementing javax.security.auth.callback.CallbackHandler and that handles
   the javax.security.auth.callback.PasswordCallback, not required for 109 cases}?
   alias={the certificate alias from the  keystore to be used for Signatures}
   aliasSelector={the fully qualified classname of a class implementing  com.sun.xml.wss.AliasSelector interface}?
   keypass={the password for the key, OR  a fully qualified classname of a class implementing javax.security.auth.callback.CallbackHandler and that handles the javax.security.auth.callback.PasswordCallback, not required for 109 cases }?
  />  

Note : ? in abstract schema definitions indicates optional attribute for the rest of this post.
Only one of  alias or aliasSelector maybe specified, if specified an AliasSelector is responsible to locating and returning the correct alias to be used for accessing the Key-Certificate pair. The alias takes precedence over aliasSelector. As you can see, the keystore location and password are not to be specified when running JSR 109 WebServices on GlassFish. This is because in this case the GlassFish JSR 196 callbackhandler knows about these values from configuration that is specific to GlassFish.  The keypass is assumed to be same as storepass in case of 109 services and hence cannot be specified.

This simple configuration has the main drawback that it requires absolute location of the keystore.   This would be a problem when one wants to move the application around on different servers. The other alternative when using static configuration is to specify a path relative to META-INF. Metro would try to locate the keystore as a resource using the call classLoader.getResource(relative-keystoreURL). This expects that the directory contaning META-INF is on the classpath.  So ideally the keystore and truststore would need to be packaged inside the WAR files and kept under WEB-INF/classes/META-INF.  The second problem is that it accepts a plain-text password which is not good for production deployment. This problem is mitigated by the fact that you can also specify a fully qualified classname of a CallbackHandler that handles the PasswordCallback in this case instead of a plain-text password.

 As one can see this simplistic configuration is good for quick development (you do not need to write any code to configure the keystore) with the exception of the problems stated above. The fact that keystore type is accepted as an argument allows developers to use either the default type JKS keystore or use other types supported by the Java KeyStore API such as PKCS11 (Hardware Tokens) and PKCS12 tokens. An example with PKCS11 was posted recently by one metro user, here is how it was configured :

I have also seen in the past PKCS12 being used as the type by another user.

When developing services for glassfish 109-deployment the keystore assertion needs to only specify the alias value and the truststore need only specify the peeralias. The other fields of the static configuration  such as storepass, type and location are ignored. Glassfish provides its own means to change the keystore location and password. The location of the keystore and truststore is specified via javax.net.ssl.keyStore and javax.net.ssl.trustStore properties in domain.xml. The password is controlled by the GlassFish MasterPassword and one limitation is that the keypassword cannot be different from the keystore password. Glassfish 109 deployments cannot make use of the Dynamic KeyStore configuration described in the next section however one can override the JSR-196 callbackhandler completely thereby providing the required level of control. Overiding the JSR-196 (JMACCallbackHandler) is described towards the end of this post.

Note the use of wspp:visibility="private" attribute, this can bee added to all the configuration assertions discussed in this document. When you use NetBeans it automatically sets the visibility attribute.

  Dynamic KeyStore Configuration

   alias={the certificate alias from the  keystore to be used for Signatures}
   aliasSelector={the fully qualified classname of a class implementing com.sun.xml.wss.AliasSelector interface}?
   callbackHandler={fully qualified classname of a class implementing javax.security.auth.callback.CallbackHandler, should be able to handle  com.sun.xml.wss.impl.callback.KeyStoreCallback and  com.sun.xml.wss.impl.callback.PrivateKeyCallback}
/>

Only one of  alias or aliasSelector are required.  This form of KeyStore configuration gives more flexibility in that you can write a CallbackHandler which handles the KeyStoreCallback and expose your keys (even those located on your filesystem or in other  stores such as NSS etc) via a Java KeyStore constructed on the fly.  This form also gets rid of the two drawbacks mentioned above with the Static KeyStore Configuration.

Static TrustStore Configuration

      location={absolute path to truststore file OR a path relative to META-INF (on the classpath), , not required for 109 cases}?
      type={type of the keystore (default is JKS)}?
      storepass={the password of the truststore as a string, OR a fully qualified classname of a class implementing javax.security.auth.callback.CallbackHandler and that handles  the javax.security.auth.callback.PasswordCallback, not required for 109 cases}?
      peeralias={the alias of the peer entity involved in secure communication, not required if no encryption is involved, never required on the server side}?
      certSelector={the fully qualified classname of a class implementing java.security.cert.CertSelector interface}?
/>

Only one of peeralias or certSelector may be specified. The description of Static TrustStore configuration is more or less similar to its corresponding KeyStore counterpart described earlier with the exception that a TrustStore accepts a  Java CertSelector as opposed to an AliasSelector. This is because the runtime primarily needs to match an incoming certificate with something in the Truststore as opposed to picking an alias. In general an alias has little utility inside a TrustStore.

 Dynamic TrustStore Configuration

      peeralias={the alias of the peer entity involved in secure communication,
      not required if no encryption is involved, never required on the server side}?
      certSelector={the fully qualified classname of a class implementing java.security.cert.CertSelector interface}?
      callbackHandler={fully qualified classname of a class implementing javax.security.auth.callback.CallbackHandler, should be able to handle
      com.sun.xml.wss.impl.callback.KeyStoreCallback to return the Truststore}
/>

Only one of peeralias or certSelector may be specified. The description of the Dynamic TrustStore is similar to that of Dynamic KeyStore above.

CertStore Configuration

      callbackHandler="{fully qualified ClassName of a class that implements
    javax.security.auth.callback.CallbackHandler interface and handles
    the com.sun.xml.wss.impl.callback.CertStoreCallback}" 
    certSelector="{fully qualified ClassName of a class that implements
    the java.security.cert.CertSelector interface}"
/>

The use of  CertStore is optional and when using it on GlassFish 109 deployments, specifying the callbackHandler attribute has no effect, this is becuase the GlassFish  JSR 196 CallbackHandler  provides its own CertStore (via a JSR 196 defined CertStoreCallback) which cannot be overridden.

 The following post by a former member explains the use of the some of these features as part of the WS-I Supply Chain Management Sample Application that we developed.

Configuration for CertificateValidator

 

  The Metro runtime has a powerful default certificate validator which uses the Java CertPathValidator API's to do certificate-chain validation for incoming certificates. The default implementation also does revocation checking based on CRL's and OCSP. By default this revocation checking is disabled and one can enable it by setting the revocationEnabled  attribute to "true" on the  ValidatorConfiguration as shown below.

sc:revocationEnabled="{If this flag is true, the default certificate revocation checking mechanism
of the underlying PKIX service provider will be used. If this flag is false,
the default revocation checking mechanism will be disabled (not used).}"?
>

Note that enabling revocation would cause certificate validation to fail if the certificates being used in the application do not have CRL distribution point or OCSP responder URL's. While this is not a problem with Production Certificates (those issued by well known CA's such as Verisign etc), it is definitely a problem if you are using experimental certificates which do not have the required certificate extensions defining these values. For example the default Metro Certificates(copyv3) do not have these extensions.

 Despite the default implementation for Certificate Validation people often find themselves in situations where they need to do additional Validations than those performed by the default implementation. For example an application may want to allow only those certificates in which a particular extension/regular attribute has a specific value. For all such cases one can configure a CertificateValidator which Metro runtime would invoke to validate the incoming certificate. The  revocationEnabled attribute defined above would then have no effect. The configuration is as shown below :

    should implement com.sun.xml.wss.impl.callback.CertificateValidationCallback.CertificateValidator,
    default Certificate validator from Metro runtime used when not supplied} /> ?

Configuration for SAML Token

 

The WS-SecurityPolicy specification defines a SAMLToken assertion which can be used as a Binding Token or as an Endorsing/Supporting token.  The configuration applicable for SAMLToken assertion is described below.

Client Side Configuration

 

http://schemas.sun.com/2006/03/wss/client">
        />

The client side configuration is a CallbackHandler that can handle the SAMLCallback. The CallbackHandler is expected to set the SAML Assertion into the SAMLCallback. If the assertion is being used and the SAML Assertion is used as a  Binding Assertion (one that is used to secure messages) then the CallbackHandler should set the AssertionID of the SAML assertion onto the Callback. See the following post for more details. Note that the details of how the SAML Assertion is obtained is out-of-scope of Metro here. The CallbackHandler may use any Protocol (ex. SAMLP etc) to obtain the SAML Assertion. We have a sample CallbackHandler that just creates new SAML Assertions on the fly (SAMLCallbackHandler.java).

Note that the SAMLCallback has two setter methods for setting the assertion.  void setAssertionElement(org.w3c.dom.Element samlAssertion) and  void setAssertionReader(XMLStreamReader samlAssertion) . It is desirable (in terms of performance) that you use the latter one if you have the assertion as an XMLStreamReader. But if the tools that you use to obtain the SAML Assertion within the CallbackHandler already return you a DOM Element then you might want to use the former. The sample SAMLCallbackHandler.java actually uses the former.        

 Server Side Configuration

 

  The server side configuration for a SAML Assertion consists primarily of a Validator.

http://schemas.sun.com/2006/03/wss/server">

    Partial validation (in the form of verifying enveloped signature) occurs on SAML Assertion within  the Metro Runtime even if the validator is not specified} /> ?

   the SAMLAssertionValidator can be used by developers to do additional validations on an incoming SAML Assertion other than verifying the signature of the Singed Assertion. See the following post for more details on the SAMLAssertionValidator.

 

Token Configuration for Kerberos Tokens

 

  A very nice Technical Tip on securing WebServices in Metro using Kerberos Tokens is here. The same information is also available in the form of blogs from our former team member here and here.

 

 

Token Configuration for IssuedToken

 

Server Side Configuration

On the server side, there are no Proprietary configuration other than  the standard IssuedToken. Please see the following detailed article.

Client Side Configuration

On the client side for trust there is a PreConfiguredSTS assertion which statically gives information about the STS that needs to be contacted by the client runtime in order to obtain the Issued Token.

  

endpoint={the endpoint URL of the STS}

wsdlLocation={the WSDL location of the STS WSDL}?

 serviceName={the service name of the STS service}?

portName={the relevant port name of the STS service to be contacted}?

namespace={the namespace of the STS WSDL}

wstVersion={ defaults to "http://docs.oasis-open.org/ws-sx/ws-trust/200512",  indicates the
version of the WS-Trust used by the STS. It is mainly used in the case that STS and the
service have different versions of WS-Trust in use.}
    shareToken={”true" indicates that the token issued for this service can be shared with the other services
    also set up with shareToken=”true".} />

 

 

One can also configure the STS on the client side at runtime instead of the static approach above. See the following posts for more details : post1, post2, post3. Another technical article that might be of use is here.

STS side Configuration

 

When using IssuedTokens there is the third party called STS (Security Token Service) and the following configuration can be specified for an STS.

"http://schemas.sun.com/ws/2006/05/trust/server"
encryptIssuedKey= {default=true, tells whether STS should encrypt the issued key}

encryptIssuedToken={default=false, tells whether STS should encrypt the Issued Token}>
     "{the lifetime of any token to be issued by this STS, in Seconds, defaults to 36000"}
     "{the fully qualified classname of the class which implements com.sun.xml.ws.api.security.trust.IssueSamlTokenContract}"
    
           
                  {the certificate alias of the certificate of the service which has trust relationship with the STS
}
                 
                    {the type of the token, defaults to urn:oasis:names:tc:SAML1.0:assertion}
                 

           
           
     

Due to its sheer complexity a detailed discussion here is not possible and  the reader is advised to refer to article links given above under this (Issued Token) section.

 

Token Configuration for SecureConversation Tokens

 

   Server Side Configuration

 

    For SecureConversation Tokens the configuration on the server side is limited to specifying the default lifetime of SecureConversation Session Tokens created by the SessionManager on the Server.

"http://schemas.sun.com/ws/2006/05/sc/server">
    {defaults to 36000 Seconds}

  Client Side Configuration

  On the client side the following configuration can be specified for a SecureConversation Token.

   "http://schemas.sun.com/ws/2006/05/sc/client">
    renewExpiredSCT

="{indicates whether to renew an expired SecureConversation Session Token automatically, default value is true}"   
     {the lifetime of the SecureConversation Session Token being requested by the Client, defaults to 36000 seconds}
 

   Please see the following article for more details.

   Overriding the DefaultCallbackHandler 

 

    I had mentioned early on in this post that when running on Non-GlassFish containers or when using Non-109 deployments on GlassFish the SecurityEnviroment implementation would make use of the Metro DefaultCallbackHandler. And this DefaultCallbackHandler has access to all the set of configurations defined in this post. One can decide to override the DefaultCallbackHandler and provide their own implementation, this can be achieved by specifying an xwssCallbackHandler as follows :

  On the Client Side :
      

<sc:CallbackHandlerConfiguration xmlns:sc="http://schemas.sun.com/2006/03/wss/client">   

       <sc:CallbackHandler  name="xwssCallbackHandler"  classname="fully qualified classname"/>  

   </sc:CallbackHandlerConfiguration>


      On the Server Side :

     

<sc:CallbackHandlerConfiguration xmlns:sc="http://schemas.sun.com/2006/03/wss/server">   

       <sc:CallbackHandler  name="xwssCallbackHandler"  classname="fully qualified classname"/>  

   </sc:CallbackHandlerConfiguration>


Note:  When one overrides the Metro DefaultCallbackHandler none of the other configuration elements described in this article/supported by the NetBeans WSIT Plugin will be relevant anymore. This is because the developer has chosen to handle all the Callbacks and Validations on his/her own.  Infact overriding the Metro DefaultCallbackHandler is not supported through NetBeans today and the developer would instead have to manually copy the above configuration into his client and server side configuration files respectively.

This is an area for future improvement since a lot of  Metro users have desired writing their own CallbackHandler in the past. We need to do two things here.

  1. Make sure that the information about other configuration assertions is available to the custom CallbackHandler, just as in the case of DefaultCallbackHandler
  2. Create a suitable BaseCallbackHandler that developers can extend from. This can be achieved by refactoring DefaultCallbackHandler. Today it is an uphill task for someone to write an xwssCallbackHandler from scratch because there are just too many callbacks to be handled even though not all of them will be needed for a given scenario.

 Use Metro WebServiceFeature to override the DefaultCallbackHandler on Client Side

   The following post describes how a Metro WebServiceFeature called CallbackHandlerFeature is being used to override the Default CallbackHandler on the Client side for (non-109 client applications). The work was done as part of using Metro to invoke an Amazon EC2 webservice.  The com.sun.xml.ws.api.security.CallbackHandlerFeature has the following constructor

public CallbackHandlerFeature(@NotNull CallbackHandler handler)

 Where one can pass in a CallbackHandler that handles the XWSS defined Callbacks (xwss-api.zip).  This saves the developer from having to write any configuration in the Metro client side configuration file. Instead it provides a programmatic alternative for overriding the client side default callbackhandler.  So here is  the CallbackHandler that was implemented for the Amazon EC2 WebService. The Policy of the WebSerivce required signing the payload using an X509 Certificate/privatekey . So you can see that the callbackhandler tries to handle only the relevant callbacks.  Infact handling the KeystoreCallback was probably not necessary in the code shown in the link.

 And here is how the WebServiceFeature is passed onto the stub during port creation (full code of the EC2 WebService client).

AmazonEC2 svc = new AmazonEC2(wsdl, new QName("http://ec2.amazonaws.com/doc/2009-04-04/", "AmazonEC2"));
        AmazonEC2PortType port = svc.getAmazonEC2Port(new CallbackHandlerFeature(
                new CertStoreCallBackImpl(loadKey(privateKey), loadX509Certificate(x509certificate))));

 Overrding the Default JSR 196 CallbackHandler on GlassFish

 

   The Default JSR 196 CallbackHandler in GlassFish  (also called as JMACCallbackHandler) makes use of  configuration information and Keying and Realm Infrastructure of GlassFish to accomplish its task of handling the JSR 196 Callbacks invoked by the Metro Runtime. Sometimes this might be too limiting for a WebService, for example someone may want to get the PrivateKey and Certificates from some other managed location. In such cases it is best to override the default JSR 196 CallbackHandler of GlassFish. This can be done by providing the following configuration :

    On the Client Side :

     

<sc:CallbackHandlerConfiguration xmlns:sc="http://schemas.sun.com/2006/03/wss/client">   

       <sc:CallbackHandler  name="jmacCallbackHandler"  classname="fully qualified classname"/>  

   </sc:CallbackHandlerConfiguration>
  

      On the Server Side :

    

<sc:CallbackHandlerConfiguration xmlns:sc="http://schemas.sun.com/2006/03/wss/server">   

       <sc:CallbackHandler  name="jmacCallbackHandler"  classname="fully qualified classname"/>  

   </sc:CallbackHandlerConfiguration>


Note: When one overrides the GlassFish Default CallbackHandler, there are still certain things which are handled by Default WSIT code. In other words the JSR 196 defined callbacks are only a SubSet of the total set of  Callbacks made by the WSIT Runtime. In such cases the configuration(s) that are mutually exclusive will continue to be relevant even if the developer has overridden the default  GlassFish CallbackHandler. The override rule for overlapping configurations would continue to apply the same way as described earlier.  Overriding the GlassFish DefaultCallbackHandler is not supported through NetBeans today and the developer would instead have to manually copy the above configuration into his client and server side configuration files respectively.

Writing a jmacCallbackHandler is much simpler because the set of Callbacks defined by JSR 196 is a small one. A sample jmacCallbackHandler configuration and the corresponding handler are shown below :

  
                   
   
 

 And here is the CallbackHandler skeleton which handles some of the JSR 196 defined Callbacks.

package simple.server;

import javax.security.auth.callback.Callback;
import javax.security.auth.callback.NameCallback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.UnsupportedCallbackException;
import javax.security.auth.message.callback.PasswordValidationCallback;
import javax.security.auth.message.callback.PrivateKeyCallback;

public class JmacCBHandler implements CallbackHandler {
        .....
    public JmacCBHandler() { ...}
    public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
        System.out.println("In server jmac callback handler : ");
        for(Callback callback: callbacks) {
            if (callback instanceof PasswordValidationCallback) {

             //handle password validation 

            } else if (callback instanceof PrivateKeyCallback) { //handle privatekey callback}

           else { //throw UnsupportedCallbackException}

       }

    }

}  

 An interesting forum discussion where the developer had used this feature of specifying a JMAC CallbackHandler again on the server side can be found here.

 

Appendix

     The complete abstract schema for CallbackHandlerConfiguration and ValidatorConfiguration elements in Metro are discussed in a later post due to content length limitations of this post.

Related Topics >>

Comments

Hi Thej, It is clumsy to discuss things as comments here. Instead can you post a question to users@metro.dev.java.net and then you should have trouble attaching things etc.

Hi, My .net WCF wsdl contains So how can i proceed with Metro? Any configuration is required? Thanks, Thej

And I am not able to upload the wsdl. could you please tell me how can i do that? Java Request: POST /ConnectorFramework HTTP/1.1 Content-Length: 1145 Content-Type: application/soap+xml; charset=utf-8 Accept: application/soap+xml, application/xop+xml, text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2 User-Agent: Java/1.5.0_08 Host: 192.168.154.27:51905 Connection: keep-alive <?xml version='1.0' encoding='utf-8'?>Test DescTest Display NameTest OMCF

Hi , we use WCF, <?xml version="1.0" encoding="utf-8"?>

Likely the request message is either directly an application message or a secure conversation RST message bu with wrong addressing Action header so that the service didn't recognize. 1. Please use Metro instead of JWSDP. 2. Do you know the software used for .Net? WCF or WSE. 3. Can you send us the service wsdsl and the request message? Thanks! Jiandong

Hi, I am trying to create a connector for Microsoft SCOM (2007) (System Center Operational Manager: helps to manage the systems in a network). The wsdl is accessible at server and able to generate stub using JWSDP2. But when i try to connect application using the generated stub, I am getting security error, Error..The security context token is expired or is not valid. The message was not processed. javax.xml.ws.soap.SOAPFaultException: The security context token is expired or is not valid. The message was not processed. at com.sun.xml.ws.encoding.soap.ClientEncoderDecoder.toMessageInfo(ClientEncoderDecoder.java:80) at com.sun.xml.ws.encoding.soap.client.SOAPXMLDecoder.toMessageInfo(SOAPXMLDecoder.java:200) at com.sun.xml.ws.protocol.soap.client.SOAPMessageDispatcher.receive(SOAPMessageDispatcher.java:549) at com.sun.xml.ws.protocol.soap.client.SOAPMessageDispatcher.doSend(SOAPMessageDispatcher.java:288) at com.sun.xml.ws.protocol.soap.client.SOAPMessageDispatcher.send(SOAPMessageDispatcher.java:153) at com.sun.xml.ws.encoding.soap.internal.DelegateBase.send(DelegateBase.java:85) at com.sun.xml.ws.client.EndpointIFInvocationHandler.implementSEIMethod(EndpointIFInvocationHandler.java:176) at com.sun.xml.ws.client.EndpointIFInvocationHandler.invoke(EndpointIFInvocationHandler.java:105) at $Proxy27.setup(Unknown Source) at Test.OmcfProxy.main(OmcfProxy.java:238) Below is the code part: ConnectorFrameworkDataAccess connectorFrameworkDataAccess = new ConnectorFrameworkDataAccess(new URL("http://a3a-mspoctst1:51905/ConnectorFramework?wsdl"),new QName("http://tempuri.org/","ConnectorFrameworkDataAccess")); IConnectorFramework port = (IConnectorFramework)connectorFrameworkDataAccess.getPort(IConnectorFramework.class); connectorInfo.setName(objectFactory.createConnectorInfoName("Test OMCF")); String connectionResult = port.setup(ObjectFactory.createConnectorInfo(connectorInfo)); Since SCOM is developed using .NET code, and trying to access webservice using .NET code, when i catch the http request using fiddler, i can see the request contains SOAP body with securitytoken details and cipher values. But in java , fiddler http response contain un authorised token details. Any suggestions are appreciated.

register as a user at users@metro.dev.java.net and post a question there.

Kumar, Thanks. Which forum? And How do I make sure get some notification? Thx. -Andy

I assume you configured the truststore in metro client configuration file ?. Also it appears some message got sent to .NET service but the server does not like the message. Can you get me the policy and message sent by metro client. Also let's take the discussion to a forum post since comments on blog are clumsy.

Kumar, I have developed a metro client against a WCF service which is using Secure Conversation using UsernameToken as the supporting token. I have imported the certificate from the URL of the wsdl to my local JAVA_HOME/jre/lib/security/cacerts store using keytool import mechanism. Next In the client after I got a port for the service from the service proxy, I using the BindingProvider to set USERNAME_PROPERTY and PASSWORD_PROPERTY in the requestContext. Then I make the call. Here is the exception I am getting: SEVERE: getPatient() encountered an exception! javax.xml.ws.soap.SOAPFaultException: An error occurred when verifying security for the message. at com.sun.xml.ws.fault.SOAP12Fault.getProtocolException(SOAP12Fault.java:221) 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 $Proxy42.getPatient(Unknown Source) at dod.mil.tma.tbibh.commons.wshelpers.PatientsServiceHelper.getPatient(PatientsServiceHelper.java:100) at func.wshelpers.PatientsServiceHelperTest.testgetPatient(PatientsServiceHelperTest.java:47) 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 org.junit.internal.runners.TestMethod.invoke(TestMethod.java:59) at org.junit.internal.runners.MethodRoadie.runTestMethod(MethodRoadie.java:98) at org.junit.internal.runners.MethodRoadie$2.run(MethodRoadie.java:79) at org.junit.internal.runners.MethodRoadie.runBeforesThenTestThenAfters(MethodRoadie.java:87) at org.junit.internal.runners.MethodRoadie.runTest(MethodRoadie.java:77) at org.junit.internal.runners.MethodRoadie.run(MethodRoadie.java:42) at org.junit.internal.runners.JUnit4ClassRunner.invokeTestMethod(JUnit4ClassRunner.java:88) at org.junit.internal.runners.JUnit4ClassRunner.runMethods(JUnit4ClassRunner.java:51) at org.junit.internal.runners.JUnit4ClassRunner$1.run(JUnit4ClassRunner.java:44) at org.junit.internal.runners.ClassRoadie.runUnprotected(ClassRoadie.java:27) at org.junit.internal.runners.ClassRoadie.runProtected(ClassRoadie.java:37) at org.junit.internal.runners.JUnit4ClassRunner.run(JUnit4ClassRunner.java:42) at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:45) at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:460) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:673) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:386) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:196) Is there anything else that I need to do? How can I get more information from the metro runtime as to the actual exception that is occurring? Thanks. -Andy