Download
FAQ History |
API
Search Feedback |
Writing SecurityEnvironmentHandlers for XWS-Security Applications
The signing and encryption operations require private-keys and certificates. An application can obtain such information in various ways, such as looking up a keystore with an alias, using the default key-pairs available with the container, looking up a truststore with an alias, etc. Similarly if an application wants to send a username-password in a
UsernameToken
, it can choose to obtain the username-password pair in various ways, such as reading from a file, prompting the user on the console, using a popup window, etc. The authentication of the username-password on the receiving application can similarly be done by plugging into existing authentication infrastructure, using a proprietary username-password database, etc.To support these possibilities, XWS-Security defines a set of
CallBack
classes and requires the application to define aCallBackHandler
to handle these callbacks. Thexwss:SecurityEnvironmentHandler
element is a compulsory child element that needs to be specified. The value of this element is the class name of a Java class that implements thejavax.security.auth.callback.CallbackHandler
interface and handles the set of callbacks defined by XWS-Security. There are a set of callbacks that are mandatory and everyCallbackHandler
needs to implement them. A few callbacks are optional and can be used to supply some fine-grained property information to the XWS-Security run-time.Because information such as private keys and certificates for signing and encryption can be obtained in various ways (looking up a keystore with an alias, using the default key-pairs available with the container, looking up a truststore with an alias, etc.), every callback defines a set of
Request
inner classes and a callback can be initialized with any of its request inner classes. A taggingRequest
interface is also defined within the callback to tag allRequest
classes. For example, the XWS-Security configuration schema defines anxwss:X509Token
element containing an optional attributecertificateAlias
. When thexwss:X509Token
element embedded inside axwss:Sign
element has acertificateAlias
attribute specified as shown in the following code snippet, the XWS-Security run-time would invoke theSecurityEnvironmentHandler
of the application with aSignatureKeyCallback
object to obtain the private-key required for the signing operation.The
SignatureKeyCallback
will be initialized by XWS-Security run-time with anAliasPrivKeyCertRequest
in the following manner:SignatureKeyCallback sigKeyCallback = new SignatureKeyCallback(new SignatureKeyCallback.AliasPrivKeyCertRequest(alias));The application's
SecurityEnvironmentHandler
implementation then needs to handle theSignatureKeyCallback
and use the alias to locate and set the private-key and X.509 certificate pair on theAliasPrivKeyCertRequest
. The following code shows how this callback is handled in thehandle()
method ofSecurityEnvironmentHandler
shipped with thesimple
sample.} else if (callbacks[i] instanceof SignatureKeyCallback) { SignatureKeyCallback cb = (SignatureKeyCallback)callbacks[i]; if (cb.getRequest() instanceof SignatureKeyCallback.AliasPrivKeyCertRequest) { SignatureKeyCallback.AliasPrivKeyCertRequest request = (SignatureKeyCallback.AliasPrivKeyCertRequest) cb.getRequest(); String alias = request.getAlias(); if (keyStore == null) initKeyStore(); try { X509Certificate cert = (X509Certificate) keyStore.getCertificate(alias); request.setX509Certificate(cert); // Assuming key passwords same as the keystore password PrivateKey privKey = (PrivateKey) keyStore.getKey(alias, keyStorePassword.toCharArray()); request.setPrivateKey(privKey); } catch (Exception e) { throw new IOException(e.getMessage()); } } else { throw new UnsupportedCallbackException(null, "Unsupported Callback Type Encountered"); } }This handler uses a keystore to locate the private key and certificate pair, and sets it using
AliasPrivKeyCertRequest
.As shown in the sample code, the
SecurityEnvironmentHandler
should throw anUnsupportedCallbackException
whenever it cannot handle aCallback
or a particularRequest
type of aCallback
.The type of
Request
with which theCallback
is initialized often depends on the information specified in the security configuration file of the application. For example if thexwss:X509Token
specified under anxwss:Sign
element did not contain thecertificateAlias
attribute, XWS-Security would invoke the application'sSecurityEnvironmentHandler
withSignatureKeyCallback.DefaultPrivKeyCertRequest
to try and obtain the default private-key and certificate pair. If theSecurityEnvironmentHandler
does not handle this request and throws anUnsupportedCallbackException
, the signature operation would fail.For more information, read the API documentation for callbacks from the <
JWSDP_HOME
>/xws-security/docs/api/com/sun/xml/wss/impl/callback/package-summary.html
. This documentation includes the list of mandatory and optional callbacks and the details of theCallback
classes and supported methods. Table 3-24 provides a brief summary of all the mandatoryCallback
classes and their associatedRequest
types.
Table 3-24 Summary of Callback classes and their Request types Callback Description Request Inner Classes Defined Methods in the Request Classes Signature
Key
Callback Used by XWS-Security run-time to obtain the private key to be used for signing the corresponding X.509 certificate. There are two ways in which an application can supply the private-key and certificate information.1. Lookup a keystore using an alias.2. Obtain the default private-key and certificate from the container/environment in which the application is running.Accordingly, there are twoRequest
inner classes with which theSignatureKeyCallback
can be initialized. 1.AliasPrivKeyCertRequest
: ACallback
initialized with this request should be handled if the private key to be used for signing is mapped to an alias.2.DefaultPrivKeyCertRequest
: ACallback
initialized with this request should be handled if there's some default private key to be used for signing. The following four methods are present in allRequest
Classes of thisCallback
:public void setPrivateKey(
PrivateKey privateKey)
public PrivateKey getPrivateKey()public void setX509Certificate(
X509Certificate certificate)
public X509Certificate
getX509Certificate() Signature
Verification
Key
Callback Obtains the certificate required for signature verification. There are currently two situations in which XWS-Security would require this Callback to resolve the certificate:1. When the signature to be verified references the key using an X.509SubjectKeyIdentifier
. For example, when the sender specifies the attributexwss:keyReferenceType="Identifier"
on thexwss:X509Token
child of thexwss:Sign
element.2. When the signature to be verified references the key using an X.509IssuerSerialNumber
. For example, when the sender specifies the attributexwss:keyReferenceType="IssuerSerialNumber"
on thexwss:X509Token
child of thexwss:Sign
element.Accordingly, there are twoRequest
inner classes with which aSignatureVerificationKeyCallback
can be initialized.Note: AdditionalRequests
may be defined in a future release. 1.X509SubjectKeyIdentifierBasedRequest
: Request for an X.509 certificate whose X.509SubjectKeyIdentifier
value is given.2.X509IssuerSerialBasedRequest
: Request for an X.509 certificate whose issuer name and serial number values are given. The following two methods are present in all theRequest
classes of thisCallback
:public void setX509Certificate(
X509Certificate certificate)public X509Certificate
getX509Certificate() Encryption
Key
Callback Obtains the certificate for key-encryption or a symmetric-key for data encryption. There are currently three situations in which XWS-Security would require thisCallback
for performing encryption:1. When thexwss:Encrypt
element contains anxwss:X509Token
child withcertificateAlias
attribute set to an alias. ThecertificateAlias
indicates that a random symmetric key is used for encryption of the specified message part and the certificate is then used to encrypt the random symmetric-key to be sent along with the message.2. When thexwss:Encrypt
element contains anxwss:X509Token
child with nocertificateAlias
attribute set on it. XWS-Security tries to obtain a default certificate from theCallback
to be used for encrypting the random symmetric key.3. When thexwss:Encrypt
element contains anxwss:SymmetricKey
child specifying thekeyAlias
attribute. This alias indicates that a symmetric key corresponding to this alias needs to be located and used for encryption of the specified message part.Accordingly, there are threeRequest
inner classes with which anEncryptionKeyCallback
can be initialized. 1.AliasX509CertificateRequest
: ACallback
initialized with this request should be handled if the X.509 certificate to be used for encryption is mapped to an alias.2.DefaultX509CertificateRequest
: ACallback
initialized with this request should be handled if there's a default X.509 certificate to be used for encryption.3.AliasSymmetricKeyRequest
: ACallback
initialized with this request should be handled if the symmetric key to be used for encryption is mapped to an alias. The following two methods are present in theAliasX509CertificateRequest
andDefaultX509CertificateRequest Request
classes of thisCallback
:public void setX509Certificate(
X509Certificate certificate)
public X509Certificate
getX509Certificate()The following methods are present in theAliasSymmetricKeyRequest
class of thisCallback
:public void setSymmetricKey(
javax.crypto.SecretKey
symmetricKey)
public javax.crypto.SecretKey
getSymmetricKey() Decryption
Key
Callback Obtains the symmetric key to be used for decrypting the encrypted data or obtaining the private-key for decrypting the encrypted random symmetric key that was sent with the message (along with the encrypted data).There are currently four situations in which XWS-Security will require thisCallback
to perform decryption.1. When theEncryptedKey
references the key (used for encrypting the symmetric key) using an X.509SubjectKeyIdentifier
. For example, when the sender specifies the attributekeyReferenceType="Identifier"
on thexwss:X509Token
child of thexwss:Encrypt
element.2. When theEncryptedKey
references the key (used for encrypting the symmetric key) using an X.509IssuerSerialNumber
. For example, when the sender specifies the attributekeyReferenceType="IssuerSerialNumber"
on thexwss:x509Token
child ofxwss:Encrypt
element. 1.X509SubjectKeyIdentifierBasedRequest
: Request for a private-key when the X.509SubjectKeyIdentifier
value for a corresponding X.509 certificate is given.2.X509IssuerSerialBasedRequest
: Request for a private key when the issuer name and serial number values for a corresponding X.509 certificate are given.3.X509CertificateBasedRequest
: Request for a private key when a corresponding X.509 certificate is given. The following two methods are present in theX509SubjectKeyIdentifierBasedRequest
,X509IssuerSerialBasedRequest
, andX509CertificateBasedRequest
Request
classes of thisCallback
:public void setPrivateKey(
PrivateKey privateKey)
public PrivateKey
getPrivateKey() Decryption
Key
Callback (continued) 3. When theEncryptedKey
contains awsse:Direct
reference to the key used for encrypting the symmetric key. This means the X.509 certificate is present as awsse:BinarySecurityToken
in the message. For example, when the sender specifies the attributekeyReferenceType="Direct"
on thexwss:x509Token
child ofxwss:Encrypt
element.4. When theEncryptedData
contains ads:keyName
reference to the symmetric key that was used for encryption. For example, when the sender specifies thexwss:SymmetricKey
child ofxwss:Encrypt
and specifies thekeyAlias
attribute on it.Accordingly, there are fourRequest
classes with which aDecryptionKeyCallback
can be initialized. 4.AliasSymmetricKeyRequest
: ACallback
initialized with this request should be handled if the symmetric key to be used for decryption is mapped to some alias. The following methods are present in theAliasSymmetricKeyRequest
class of thisCallback
:public void setSymmetricKey(
javax.crypto.SecretKey
symmetricKey)
public javax.crypto.SecretKey
getSymmetricKey() Password
Validation
Callback Username-Password validation. A validator that implements thePasswordValidator
interface should be set on the callback by the callback handler.There are currently two situations in which XWS-Security will require thisCallback
to perform username-password validation:1. When the receiver gets aUsernameToken
with plain-text user name and password.2. When the receiver gets aUsernameToken
with a digested password (as specified in the WSS UsernameToken Profile).Accordingly there are two Request classes with which thePasswordValidationCallback
can be initialized.Note: A validator for WSS Digested Username-Password is provided as part of this callback, with classnamePasswordValidationCallback
.DigestPasswordValidator
.This class implements WSS digest password validation. The method for computing password digest is described inhttp://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0.pdf
.For more information, see theServerSecurityEnvironmentHandler
in <JWSDP_HOME
>/xws-security/samples/jaas-sample/src/com/sun/xml/wss/sample
. 1.PlainTextPasswordRequest
: Represents a validation request when the password in the username token is in plain text.2.DigestPasswordRequest
: Represents a validation request when the password in the username token is in digested form. The following methods are present in thePlainTextPasswordRequest
:public String getUsername()
public String getPassword()
The following methods are present in theDigestPasswordRequest
:public void setPassword(String password)
This method must be invoked by theCallbackHandler
while handling aCallback
initialized withDigestPasswordRequest
to set the plain-text password on theCallback
.public java.lang.String
getPassword()public java.lang.String
getUsername()public java.lang.String getDigest()
public java.lang.String getNonce()
public java.lang.String getCreated()
Username
Callback To supply the user name for theUsernameToken
at run-time. It contains the following two methods:public void setUsername(
String username)
public String getUsername()
Refer to theClientSecurityEnvironmentHandler
of thejaas-sample
sample located in<JWSDP_HOME
>/xws-security/samples/jaas-sample/src/com/sun/xml/wss/sample
for more details on using theUsernameCallback
. PasswordCallback To supply the password for the username token at run-time. It contains the following two methods:public void setPassword(String
password)public String getPassword()
Refer to theClientSecurityEnvironmentHandler
of thejaas-sample
sample located in<JWSDP_HOME
>/xws-security/samples/jaas-sample/src/com/sun/xml/wss/sample
for more details on using thePasswordCallback
. Property
Callback Optional callback to specify the values of properties configurable with XWS-Security run-time.Refer to the API documentation at<JWSDP_HOME>
/xws-security/docs/api/com/sun/xml/wss/impl/callback/PropertyCallback.html
for a list of configurable properties methods supported by this callback. Prefix
Namespace
Mapping
Callback Optional callback to register any prefix versus namespace-uri mappings that the developer wants to make use of in the security configuration (while specifyingTargets
asxpaths
).Refer to the API documentation at<JWSDP_HOME>
/xws-security/docs/api/com/sun/xml/wss/impl/callback/PrefixNamespaceMappingCallback.html
for more details.
The following code snippet shows the
handle()
method skeleton for an application'sSecurityEnvironmentHandler
that handles all the mandatoryCallbacks
(exceptUsernameCallback
andPasswordCallback
) and associatedRequests
defined by XWS-Security. A particular application may choose to throw anUnsupportedCallbackException
for any of theCallbacks
or itsRequests
that it cannot handle. TheUsernameCallback
andPasswordCallback
are useful for obtaining a username-password pair at run-time and are explained later in this section.
Note: In this release of XWS-Security, users will have to ensure that the
SecurityEnvironmentHandler
implementation they supply is thread safe.public class SecurityEnvironmentHandler implements CallbackHandler { public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException { for (int i=0; i < callbacks.length; i++) { if (callbacks[i] instanceof PasswordValidationCallback) { PasswordValidationCallback cb = (PasswordValidationCallback) callbacks[i]; if (cb.getRequest() instanceof PasswordValidationCallback.PlainTextPasswor dRequest) { // setValidator for plain-text password validation on callback cb } else if (cb.getRequest() instanceof PasswordValidationCallback.DigestPasswor dRequest) { PasswordValidationCallback.DigestPasswordRequest request = (PasswordValidationCallback.DigestPasswordRequest) cb.getRequest(); // set plaintext password on request // setValidator for digest password validation on cb } else { // throw unsupported; } } else if (callbacks[i] instanceof SignatureVerificationKeyCallback) { SignatureVerificationKeyCallback cb = (SignatureVerificationKeyCallback)callbacks [i]; if (cb.getRequest() instanceof SignatureVerificationKeyCallback.X509Subjec tKeyIdentifierBasedRequest) { // subject keyid request SignatureVerificationKeyCallback.X509SubjectKeyIdentifierBased Request request = (SignatureVerificationKeyCallback.X509SubjectKeyIdentifierBase dRequest) cb.getRequest(); // locate and setX509Certificate on the request } else if (cb.getRequest() instanceof SignatureVerificationKeyCallback.X509Iss uerSerialBasedRequest) { // issuer serial request SignatureVerificationKeyCallback.X509IssuerSerialBasedRequest request = (SignatureVerificationKeyCallback.X509IssuerSerialBasedRequest ) cb.getRequest(); // locate and setX509Certificate on the request } else { // throw unsupported; } } else if (callbacks[i] instanceof SignatureKeyCallback) { SignatureKeyCallback cb = (SignatureKeyCallback)callbacks[i]; if (cb.getRequest() instanceof SignatureKeyCallback.DefaultPrivKeyCertRequest) { // default priv key cert req SignatureKeyCallback.DefaultPrivKeyCertRequest request = (SignatureKeyCallback.DefaultPrivKeyCertRequest) cb.getRequest(); // locate and set default privateKey and X509Certificate on request } else if (cb.getRequest() instanceof SignatureKeyCallback.AliasPrivKeyCertRequest) { // Alias priv key cert req SignatureKeyCallback.AliasPrivKeyCertRequest request = (SignatureKeyCallback.AliasPrivKeyCertRequest) cb.getRequest(); // locate and set default privateKey and X509Certificate on request } else { // throw unsupported; } } else if (callbacks[i] instanceof DecryptionKeyCallback) { DecryptionKeyCallback cb = (DecryptionKeyCallback)callbacks[i]; if (cb.getRequest() instanceof DecryptionKeyCallback.X509SubjectKeyIdentif ierBasedRequest) { //ski request DecryptionKeyCallback.X509SubjectKeyIdentifierBasedRequest request = (DecryptionKeyCallback.X509SubjectKeyIdentifierBasedRequest) cb.getRequest(); // locate and set the privateKey on the request } else if (cb.getRequest() instanceof DecryptionKeyCallback.X509IssuerSerialBas edRequest) { // issuer serial request DecryptionKeyCallback.X509IssuerSerialBasedRequest request = (DecryptionKeyCallback.X509IssuerSerialBasedRequest) cb.getRequest(); // locate and set the privateKey on the request } else if (cb.getRequest() instanceof DecryptionKeyCallback.X509CertificateBas edRequest) { // X509 cert request DecryptionKeyCallback.X509CertificateBasedRequest request = (DecryptionKeyCallback.X509CertificateBasedRequest) cb.getRequest(); // locate and set private key on the request } else if (cb.getRequest() instanceof DecryptionKeyCallback.AliasSymmetricKeyR equest) { DecryptionKeyCallback.AliasSymmetricKeyRequest request = (DecryptionKeyCallback.AliasSymmetricKeyRequest) cb.getRequest(); // locate and set symmetric key on request } else { // throw unsupported; } } else if (callbacks[i] instanceof EncryptionKeyCallback) { EncryptionKeyCallback cb = (EncryptionKeyCallback)callbacks[i]; if (cb.getRequest() instanceof EncryptionKeyCallback.AliasX509CertificateRequest) { EncryptionKeyCallback.AliasX509CertificateRequest request = (EncryptionKeyCallback.AliasX509CertificateRequest) cb.getRequest(); // locate and set certificate on request } else if (cb.getRequest() instanceof EncryptionKeyCallback.AliasSymmetricKeyRe quest) { EncryptionKeyCallback.AliasSymmetricKeyRequest request = (EncryptionKeyCallback.AliasSymmetricKeyRequest) cb.getRequest(); // locate and set symmetric key on request } else { // throw unsupported; } } else if (callbacks[i] instanceof CertificateValidationCallback) { CertificateValidationCallback cb = (CertificateValidationCallback)callbacks[i]; // set an X509 Certificate Validator on the callback } else { // throw unsupported; } } } }
An application can also choose not to handle certain callbacks if it knows that the particular application will never require those callbacks. For example if the security application only deals with signing the requests and does not deal with encryption or username tokens, its
handle()
method only needs to worry aboutSignatureKeyCallback
(with its associatedRequests
) andSignatureVerificationKeyCallback
(with its associatedRequests
). It can then throw anUnsupportedCallbackException
for any other callback. The following code shows thehandle()
method skeleton for such an application:public class SecurityEnvironmentHandler implements CallbackHandler { public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException { for (int i=0; i < callbacks.length; i++) { if (callbacks[i] instanceof SignatureVerificationKeyCallback) { SignatureVerificationKeyCallback cb = (SignatureVerificationKeyCallback)callbacks [i]; if (cb.getRequest() instanceof SignatureVerificationKeyCallback.X509Subjec tKeyIdentifierBasedRequest) { // subject keyid request SignatureVerificationKeyCallback.X509SubjectKeyIdentifierBased Request request = (SignatureVerificationKeyCallback.X509SubjectKeyIdentifierBase dRequest) cb.getRequest(); // locate and setX509Certificate on the request } else if (cb.getRequest() instanceof SignatureVerificationKeyCallback.X509Issu erSerialBasedRequest) { // issuer serial request SignatureVerificationKeyCallback.X509IssuerSerialBasedRequest request = (SignatureVerificationKeyCallback.X509IssuerSerialBasedRequest ) cb.getRequest(); // locate and setX509Certificate on the request } else { // throw unsupported; } } else if (callbacks[i] instanceof SignatureKeyCallback) { SignatureKeyCallback cb = (SignatureKeyCallback)callbacks[i]; if (cb.getRequest() instanceof SignatureKeyCallback.DefaultPrivKeyCertRequest) { // default priv key cert req SignatureKeyCallback.DefaultPrivKeyCertRequest request = (SignatureKeyCallback.DefaultPrivKeyCertRequest) cb.getRequest(); // locate and set default privateKey and X509Certificate on request } else if (cb.getRequest() instanceof SignatureKeyCallback.AliasPrivKeyCertRequest) { // Alias priv key cert req SignatureKeyCallback.AliasPrivKeyCertRequest request = (SignatureKeyCallback.AliasPrivKeyCertRequest) cb.getRequest(); // locate and set default privateKey and X509Certificate on request } else { // throw unsupported; } } else { // throw unsupported; } } } }Similarly, an application dealing only with
UsernameToken
but not signature or encryption requirements can simply throwUnsupportedCallbackException
for all non-username related callbacks.The
SecurityEnvironmentHandler
implementation for thesimple
sample is located in the directory<JWSDP_HOME>
/xws-security/samples/simple/src/com/sun/xml/wss/sample
. Thesimple
sample uses the sameSecurityEnvironmentHandler
for both the client and server side.The
jaas-sample
sample requires a different set of callbacks to be handled on the client and server side. TheCallbackHandlers
for thejaas-sample
sample are located in the directory<JWSDP_HOME>
/xws-security/samples/jaas-sample/src/com/sun/xml/wss/sample
. The twoCallbackHandlers
defined for thejaas-sample
are:
- A
ClientSecurityEnvironmentHandler
that handles only theUsernameCallback
andPasswordCallback
for retrieving the username and password to be sent in a WSSUsernameToken
.- A
ServerSecurityEnvironmentHandler
that handles only thePasswordValidationCallback
to validate the username-password pair that it received in the WSSUsernameToken
.Using the SubjectAccessor API
XWS-Security applications might require access to the authenticated subject of the sender from within the SEI implementation methods. The
SubjectAccessor
API contains a single method:This method returns the
Subject
if one is available or else it returnsNULL
. The context argument to be passed into this method is theServletEndpointContext
which is available with the SEI implementation class. For an example on how theSubjectAccessor
is used to obtain the authenticated sender subject, refer to thePingImpl.java
class in thejaas-sample
sample located at<JWSDP_HOME>
/xws-security/samples/jaas-sample/server/src/sample
. The API forSubjectAccessor
viewed from<JWSDP_HOME>
/xws-security/docs/api/com/sun/xml/wss/SubjectAccessor.html
.
Download
FAQ History |
API
Search Feedback |
All of the material in The Java(TM) Web Services Tutorial is copyright-protected and may not be published in other works without express written permission from Sun Microsystems.