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. Metro attempts to move this binding to a standard API JSR 196 CallbackHandler and Callbacks defined by the JSR. 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. 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. There is still scope for refining and repackaging the current Metro Security Token configuration framework but i have been spending less time on it due to my GlassFish Security engagements for the last 2 years. This post is very informal (not so well organized) and is a prelude to Documentation that would appear with Metro 2.0 Final Release. 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.
<sc:ValidatorConfiguration ../>
<sc:Validator name="timestampValidator" classname ={class name of a Timestamp Validator,
should implement com.sun.xml.wss.impl.callback.TimestampValidationCallback.TimestampValidator,
a default Timestamp validator from XWSS runtime is used when not supplied} />
</sc:ValidatorConfiguration>
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
- Standalone Java Clients
- WebApplications/WebServices acting as client to another WebService
- Java EE Application Clients
Standalone Java Clients
The configuration possible for Standalone Java Client's is two fold
- Programmatic Username and Password supplied as properties on the BindingProvider.RequestContext. This kind of configuration is shown in my earlier post here.
- described in the following abstract schema
<sc:CallbackHandlerConfiguration
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}" >
<sc:CallbackHandler name="usernameHandler" classname="{a callbackhandler classname that handles javax.security.auth.callback.NameCallback}"
default="{the default username value as a string, to be provided incase classname is not provided}"/>
<sc:CallbackHandler name="passwordHandler" classname="{a callbackhandler classname that handles javax.security.auth.callback.PasswordCallback}"
default="{the default password value as a string, to be provided incase classname is not provided}" />
</sc:CallbackHandlerConfiguration>
So one can either specify a default username and password
<sc:CallbackHandlerConfiguration xmlns:sc="http://schemas.sun.com/2006/03/wss/client" >
<sc:CallbackHandler name="usernameHandler" default="<my username>"/>
<sc:CallbackHandler name="passwordHandler" default="<my password>" />
</sc:CallbackHandlerConfiguration>
or specify a Username and Password Handler separately as below
<sc:CallbackHandlerConfiguration xmlns:sc="http://schemas.sun.com/2006/03/wss/client" >
<sc:CallbackHandler name="usernameHandler" classname="my.UsernameCallbackHandler"/>
<sc:CallbackHandler name="passwordHandler" classname="my.PasswordCallbackHandler" />
</sc:CallbackHandlerConfiguration>
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 :
- Token Issuer
- 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
- Programmatic Username and Password supplied as properties on the BindingProvider.RequestContext. This kind of configuration is shown in my earlier post here.
- 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.
<sc:CallbackHandlerConfiguration xmlns:sc="http://schemas.sun.com/2006/03/wss/client" >
<sc:CallbackHandler name="usernameHandler" default="<my username>"/>
<sc:CallbackHandler name="passwordHandler" default="<my password>" />
</sc:CallbackHandlerConfiguration>
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".
<sc:CallbackHandlerConfiguration xmlns:sc="http://schemas.sun.com/2006/03/wss/client" >
<sc:CallbackHandler name="usernameHandler" default="xyz"/>
<sc:CallbackHandler name="passwordHandler" default="$xyzpasswordalias" />
</sc:CallbackHandlerConfiguration>
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
- Programmatic Username and Password supplied as properties on the BindingProvider.RequestContext (same as with other types of clients above)
- Use the GlassFish Default AppClient CallbackHandler for collecting the Username/Password
- 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
- Validation of the Username-Password pair and setting the corresponding caller principal which can be used for authorization purposes
- 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.
- 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.
- Username Token containing the hashed password (also known as Password Digest Authentication).
- 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
- GlassFish 109 deployment
- 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
- 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.
- A RealmAuthentication Adapter can be specified.
A ValidatorConfiguration with a usernameValidator child on the server side WSDL has the following abstract schema.
<sc:ValidatorConfiguration ...>
<sc:Validator name= "usernameValidator" classname={class name of a usernameToken Validator,
should implement com.sun.xml.wss.impl.callback.PasswordValidationCallback.PasswordValidator a sample validator can be seen here}/>
</sc:ValidatorConfiguration>
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:ValidatorConfiguration
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
<sc: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 :
<sc1:KeyStore wspp:visibility="private" alias="Sign_Keypair" storepass="12345678" type="PKCS11" location=""/>
I have also seen in the past PKCS12 being used as the type by another user.
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
<sc:Keystore
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
<sc:Truststore
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
<sc:Truststore
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
<sc:CertStore
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:ValidatorConfiguration
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 :
<sc:ValidatorConfiguration
<sc:Validator name="certificateValidator" classname ={class name of a certificate Validator,
should implement com.sun.xml.wss.impl.callback.CertificateValidationCallback.CertificateValidator,
default Certificate validator from Metro runtime used when not supplied} /> ?
</sc:ValidatorConfiguration>
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
<sc:CallbackHandlerConfiguration ...xmlns:sc="http://schemas.sun.com/2006/03/wss/client">
<sc:CallbackHandler name="samlHandler" classname="{a callbackhandler classname that
handles com.sun.xml.wss.impl.callback.SAMLCallback}"
/>
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 <sp:ProtectTokens/> 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.
<sc:ValidatorConfiguration .... xmlns:sc="http://schemas.sun.com/2006/03/wss/server">
<sc:Validator name="samlAssertionValidator" classname = {class name of a SAML Assertion Validator, should implement com.sun.xml.wss.impl.callback.SAMLAssertionValidator,
Partial validation (in the form of verifying enveloped signature) occurs on SAML Assertion within the Metro Runtime even if the validator is not specified} /> ?
</sc:ValidatorConfiguration>
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.
<tc:PreconfiguredSTS xmlns:tc="http://schemas.sun.com/ws/2006/05/trust/client"
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.
<tc:STSConfiguration xmlns:tc="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}>
<tc:LifeTime>"{the lifetime of any token to be issued by this STS, in Seconds, defaults to 36000"}</tc:LifeTime>
<tc:Contract>"{the fully qualified classname of the class which implements com.sun.xml.ws.api.security.trust.IssueSamlTokenContract}"</tc:Contract>
<tc:ServiceProviders>
<tc:ServiceProvider endPoint="service-endpoint-uri" >
<tc:CertAlias>{the certificate alias of the certificate of the service which has trust relationship with the STS }</tc:CertAlias>
<tc:TokenType>
{the type of the token, defaults to urn:oasis:names:tc:SAML1.0:assertion}
</tc:TokenType>
</tc:ServiceProvider>
<!-- more service providers -->
<tc:ServiceProviders>
</tc:STSConfiguration>
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.
<scc:SCConfiguration xmlns:tc="http://schemas.sun.com/ws/2006/05/sc/server">
<scc:LifeTime>{defaults to 36000 Seconds}</scc:LifeTime>
</scc:SCConfiguration>
Client Side Configuration
On the client side the following configuration can be specified for a SecureConversation Token.
<scc:SCConfiguration xmlns:tc="http://schemas.sun.com/ws/2006/05/sc/client">
renewExpiredSCT="{indicates whether to renew an expired SecureConversation Session Token automatically, default value is true}"
<scc:LifeTime>{the lifetime of the SecureConversation Session Token being requested by the Client, defaults to 36000 seconds}</scc:LifeTime>
</scc:SCConfiguration>
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.
- Make sure that the information about other configuration assertions is available to the custom CallbackHandler, just as in the case of DefaultCallbackHandler
- 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 :
<sc:CallbackHandlerConfiguration xmlns:sc="http://schemas.sun.com/2006/03/wss/server" wspp:visibility="private">
<sc:CallbackHandler name="jmacCallbackHandler" classname="simple.server.JmacCBHandler" />
</sc:CallbackHandlerConfiguration>
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
Here is the complete abstract schema for CallbackHandlerConfiguration and ValidatorConfiguration elements in Metro. I decided to paste the complete configuration here because for these two elements the configuration has been shown in bits and pieces under different tokens (as relevant).
<sc:CallbackHandlerConfiguration wspp:visibility="private" xmlns:sc="http://schemas.sun.com/2006/03/wss/{server or client}"
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}"
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}" >
<sc:CallbackHandler name="usernameHandler" classname="{a callbackhandler classname that handles javax.security.auth.callback.NameCallback}"
default="{the default username value as a string, to be provided incase classname is not provided}" />
<sc:CallbackHandler name="passwordHandler" classname="{a callbackhandler classname that handles javax.security.auth.callback.PasswordCallback}"
default="{the default password value as a string, to be provided incase classname
is not provided}" />
<sc:CallbackHandler name="samlHandler" classname="{a callbackhandler classname that handles com.sun.xml.wss.impl.callback.SAMLCallback}"/>
<sc:CallbackHandler name="jmacCallbackHandler" classname="{a callbackhandler classname that handles all the Standard JSR 196 Callbacks}" />
<sc:CallbackHandler name="xwssCallbackHandler" classname="{a callbackhandler classname that handles all the XWSS Callbacks}" />
</sc:CallbackHandlerConfiguration>
<sc:ValidatorConfiguration wspp:visibility="private" xmlns:sc="http://schemas.sun.com/2006/03/wss/{server or client}"
sc:maxClockSkew="{The assumed maximum skew (milliseconds) between the local times of any two systems, runtime defaults used when not specified}"
sc:timestampFreshnessLimit="{The period (milliseconds) for which a Timestamp is considered fresh, runtime defaults used when not specified }
sc:maxNonceAge="{The length of time (milliseconds) a previously received Nonce value in a UsernameToken will be stored, runtime defaults used when not specified}"
sc:revocationEnabled="{If this flag is true, the default certificate revocation checking mechanism of the underlying PKIX service provider will be used. If this f