9 Oracle Web Services Security
Oracle Web Services Security provides a complete implementation of the OASIS WS Security 1.1 standard. It provides mechanisms to sign and encrypt messages, and security tokens to ascertain the sender's identity.
This chapter describes how to install and use the SDK. This chapter contains these topics:
9.1 Setting Up Your Oracle Web Services Security Environment
You can setup Oracle Web Services Security environment by installing Oracle Security Developer Tools and Java Development Kit (JDK), and setting the CLASSPATH
variable to all the required jar files.
The Oracle Security Developer Tools are installed with Oracle Application Server in ORACLE_HOME
.
To use Oracle Web Services Security, you must have Development Kit (JDK) version 1.6 or higher.
Make sure the following items are included in your CLASSPATH
:
-
osdt_core.jar
-
osdt_cert.jar
-
osdt_xmlsec.jar
- This is the Oracle XML Security jar. -
osdt_saml.jar
- This is the Oracle SAML 1.0 and 1.1 jar. -
osdt_saml2.jar
- This is the Oracle SAML 2.0 jar. -
org.jaxen_1.1.1.jar,
which is included in$ORACLE_HOME/modules/
. -
osdt_wss.jar
- This is the main jar containing Oracle Web Services Security. -
saaj-api.jar
- This is the standard SAAJ API and is included in JDK6; for previous JDKs, you can obtain it from your JavaEE container. -
mail.jar, activation.jar
- You can obtain these jars from your JavaEE container.
See Also:
9.2 Classes and Interfaces of Oracle Web Services Security
Oracle Web Services Security provides classes, interfaces, and methods to sign and encrypt messages, and security tokens to ascertain the sender's identity.
Note:
Review Oracle XML Security before proceeding.
This section describes classes and interfaces in the Oracle Web Services Security API. It contains these topics:
9.2.1 Element Wrappers in Oracle Web Services Security
Oracle Web Services Security provides element wrappers to all XML elements.
Table 9-1 lists the element wrappers provided by Oracle Web Services Security.
Table 9-1 Element Wrappers for Oracle Web Services Security
XML Tag Name | Java Class Name |
---|---|
<wsse:Security> |
oracle.security.xmlsec.wss.WSSecurity |
<wsse:BinarySecurityToken> |
oracle.security.xmlsec.wss.WSSBinarySecurityToken or one of its derived classes depending on the valueType attribute: oracle.security.xmlsec.wss.x509.X509BinarySecurityToken oracle.security.xmlsec.wss.kerberos.KerberosBinarySecurityToken |
<wsse: SecurityTokenReference> |
oracle.security.xmlsec.wss.WSSecurityTokenReference |
<wsse: Embedded> |
oracle.security.xmlsec.wss.WSSEmbedded |
<wsse11:EncryptedHeader> |
oracle.security.xmlsec.wss.WSSEncryptedHeader |
<wsse11:SignatureConfirmation> |
oracle.security.xmlsec.wss.WSSignatureConfirmation |
<wsse:KeyIdentifier> |
oracle.security.xmlsec.wss.WSSKeyIdentifier or one of its derived classes depending on the valueType attribute: oracle.security.xmlsec.wss.x509.X509KeyIdentifier oracle.security.xmlsec.wss.saml.SAMLAssertionKeyIdentifier oracle.security.xmlsec.wss.saml2.SAML2AssertionKeyIdentifier oracle.security.xmlsec.wss.kerberos.KerberosKeyIdentifier oracle.security.xmlsec.wss.WSSEncryptedKeyIdentifier |
<wsse:Reference> |
oracle.security.xmlsec.wss.WSSReference |
<wsu:Created> |
oracle.security.xmlsec.wss.WSUCreated |
<wsu:Expires> |
oracle.security.xmlsec.wss.WSUExpires |
<wsu:Timestamp> |
oracle.security.xmlsec.wss.WSUTimestamp |
<wsse:UsernameToken> |
oracle.security.xmlsec.wss.username.UsernameToken oracle.security.xmlsec.wss. oracle.security.xmlsec.wss. oracle.security.xmlsec.wss. oracle.security.xmlsec.wss. oracle.security.xmlsec.wss. oracle.security.xmlsec.wss. |
As explained in Understanding and Using Element Wrappers in the OSDT XML APIs, the java classes are only throwaway wrappers, while the DOM elements are the source of truth. You can create these wrapper classes using the appropriate constructor, which takes in the DOM element; you can get the underlying DOM element using the getElement
method.
9.2.2 The <wsse:Security> header
The WS Security specification defines a new SOAP Header called <wsse:Security>. All security information, such as Security Tokens, Timestamp, Signatures, EncryptedKeys, and ReferenceList, are stored inside this header.
-
Security Tokens - Contain user name tokens, certificates, SAML assertion and so on (see next section)
-
Timestamp - The current time stamp is often included in the security header, and it is usually included in a signature to prevent replay attacks.
-
Signatures - Any signatures are stored inside the header. Even though the signature is in the
Security
header, what it signs is often outside the header - for example, a single signature can sign the SOAP Body, some SOAP attachments, aUserName
token inside theSecurity
header, and aTimestamp
token in theSecurity
header. -
EncryptedKeys - Any encrypted session keys are stored here.
-
ReferenceList - Contains a list of all the
EncryptedData
sections.
9.2.2.1 Handling Outgoing Messages
For outgoing messages, you need to create a new <wsse:Security>
header, add security tokens and then encrypt and/or sign parts of the document. Here is how to accomplish this task:
// Assuming we the outgoing message has already been constructed into // a SOAPMessage object (part of SAAJ API) SOAPMessage msg = ... // Now create a new <wsse:Security> Header // newInstance will internally use SOAPHeader.addHeaderElement SOAPEnvelope env = msg.getSOAPPart().getEnvelope(); WSSecurity ws = WSSecurity.newInstance(env); // Add required prefixes to this SOAP header // Now add some security tokens (refer to the next section on // how to create security tokens) UsernameToken ut = ... ws.addUsernameToken(ut); // Create some security token references to this token // (refer to following sections) ws.createSTR... // Now sign or encrypt some data (refer to following sections) // These should use the above STRs ws.sign(...); ws.encryptWithEncKey(...); ws.encryptNoEncKey(...);
9.2.2.2 Handling Incoming Messages
For incoming messages, you need to look for a particular <wsse:Security>
header, inspect its contents, and verify or decrypt parts of the document. To accomplish this task:
// Assuming we the incoming message has already been constructed into // a SOAPMessage object (part of SAAJ API) SOAPMessage msg = ...
9.2.3 Security Tokens (ST) in Oracle Web Services Security
A security token represents an artifact such as a certificate, a kerberos ticket, a user name with password, a Single sign-on token and so on. Oracle Web Services Security contains different types security tokens, such as Username token, X509 certificate, Kerberos ticket, and SAML Assertion, with multiple variations.
Usually a key is derived/extracted from this token, and this key is used to encrypt/decrypt sign/verify parts of the message. However, the security token can also be used just as a data object.
Table 9-2 Security Tokens for Oracle Web Services Security
Type of Token (Java Class) | Variations | Keys |
---|---|---|
Username token oracle.security.xmlsec.wss.username. UsernameToken |
|
Symmetric key obtained by running KeyDerivation on user's password |
X509 certificate oracle.security.xmlsec.wss.x509. X509BinarySecurityToken |
|
|
Kerberos ticket oracle.security.xmlsec.wss.kerberos. KerberosBinarySecurityToken |
|
Either the session key present in the ticket, or a subkey. |
SAML Assertion 1.1 oracle.security.xmlsec.wss.saml.SAMLAssertionToken SAML Assertion 2.0 oracle.security.xmlsec.wss.saml2. SAML2AssertionToken |
|
For holder_of_key the subject's key is used – this is, the key inside the <saml:SubjectConfirmation> which is inside the <saml:Assertion>. For sender_vouches, the key of the attesting entity is used. Keys are not extracted from bearer tokens. |
9.2.3.1 Creating a WSS Username Token
First, create a UsernameToken
and place it inside your WSSecurity
header. The only mandatory field in the UsernameToken
is the username:
// create a Username token WSSecurity ws = ... UsernameToken ut = new UsernameToken(doc); ut.setUserName("Zoe"); // remember to put this inside your WSSecurity header. // addUserNameToken puts it at the beginning, you can also // use a regular DOM method appendChild or insertChild to put it in. ws.addUsernameToken(ut); // optionally add an wsu:Id, so you can refer to it ut.setWsuId("MyUser");
Next, decide how to put the password into this token. There are several choices:
- Add a clear text password. Consider using this technique only when the whole message is being sent over a secure channel like SSL.
- Add a digest of the password or some other kind of derived password. A digest is not necessarily more secure than a clear text password, as it can also be replayed unless it is protected by a nonce and time.
- Add a digest of the password using the digest mechanism given in the WS Security specification. This uses the nonce and the
createdDate
. - Do not add the password or its digest at all. Instead derive a key from the password and use that to sign the message, to demonstrate knowledge of the key.
// For options 1 and 2, use the setPassword method ut.setPassword("IloveDogs"); // With this mechanism, the reciever should simply call // UsernameToken.getPassword to check if the password is as expected. // For option 3, use the setPasswordDigest method, but before doing // thatfor that you have to at first set a nonce and a created date. SecureRandom random = SecureRandom.getInstance("SHA1PRNG"); byte nonce[] = new byte[20]; random.nextBytes(nonce); // compute a 20 byte random nonce ut.setNonce(nonce); ut.setCreatedDate(new Date()); // Set the date to now ut.setPasswordDigest("IloveDogs"); // will compute the digest from // this clear text password using // nonce and createdDate // For this mechanism, the reciever should use the following byte nonce[] = ut.getNonce(); .. check against the used nonces, to make sure this is a new nonce Date createdDate = ut.getCreated(); .. check that this createdDate is within an expected clock skew boolean valid = ut.isValid(userName, passwd), // above call will recompute the digest from the passwd // and the nonce and created date, and check if this digest matches // the digest in the username token // For option 4, set the salt and iteration count SecureRandom random = SecureRandom.getInstance("SHA1PRNG"); byte salt[] = new byte[15]; random.nextBytes(salt); // compute a 15 byte random salt ut.setSalt(1, salt); ut.setIteration(1000); SecretKey key = ut.deriveKey("IloveDogs");
Now you can use this secret key to sign or encrypt data.
9.2.3.2 Creating an X509 Token
You can either use the X509BinarySecurityToken
constructor followed by the setToken
method, or use the equivalent helper method WSSecurity.createBST_X50
9:
WSSecurity ws = ... X509Certificate cert = ... X509BinarySecurityToken x509token = WSSecurity.createBST_X509(cert); // remember to put this inside your WSSecurity header. // addX509CertificateToken puts it at the beginning, you can also // use a regular DOM method appendChild or insertChild to put it in. ws.addX509CertificateToken(x509Token); // optionally add an wsu:Id, so you can refer to it x509Token.setWsuId("MyCert");
You can also create an X509BinarySecurityToken
from a CertPath
object if you want to include an entire chain of certificates.
For encryption data with this certificate, you need the public key which you can obtain by using cert.getPublicKey()
. For signing, however, you need the private key, which you should maintain in a keystore.
9.2.3.3 Creating a Client-Side Kerberos Token
Kerberos tokens are used, as a rule, in conjunction with the Java GSS-API.
This example shows how to create a client-side token:
//Use JAAS Authentication with Kerberos Login Module // Set up the config files and then call login() // to login using this module. This will cause the client to contact // the Kerberos Authentication-Service and get a ticket to talk to the // Kerberos Ticket-Granting-Service LoginContext lc = new LoginContext(...); lc.login(); //Use JAAS Authorization to set the subject into the thread context Subject.doAs(lc.getSubject(), action) // The rest of the code should be executed as a Privileged action // Create a GSSContext to talk to a particular server. GSSManager gssManager = GSSManager.getInstance(); GSSName serviceName = gssManager.createName(svcPrincipalName, null); GSSContext gssContext = gssManager.createContext(serviceName, null, null, GSSCredential.DEFAULT_LIFETIME); // Then call initSecContext. this will cause the client to contact // the Ticket-Granting-Service to obtain a ticket for talking to that // particular server. The token that is returned by the initSecContext // is a GSS wrapped AP_REQ packet. byte[] token = new byte[1]; token = gssContext.initSecContext(token, 0, token.length); // Create a Kerberos BST using this AP_REQ packet WSSecurity ws = ... KerberosBinarySecurityToken kbst = ws.createBST_Kerberos(token, WSSURI.vt_GSSKerberosv5); ws.addKerberosToken(kbst); // Get the sessionKey that is present inside the AP_REQ packet, // this is the session that is generated by the TGT and returned // to the client in the initSecContext class // // This getSessionKey call simply calls Subject.getPrivateCredentials // to get a list of tickets associated with the subject, and then // iterates through them to find the one to be used for // for that particular server SecretKey sessionKey = KerberosUtils.getSessionKey(lc.getSubject(),svcPrincipalName);
Now you can use this secret key to sign or encrypt data.
Server Side
9.2.3.4 Creating a Server-side Kerberos Token
Server-side kerberos tokens require creation of the GSSContext and extraction of the session key.
This example shows how to create a server-side kerberos token:
// Use JAAS Authentication and Authorization as for the client // Create GSSContext will null credentials </b><br> SSManager manager = GSSManager.getInstance(); GSSContext gssContext = manager.createContext((GSSCredential)null); // Locate the KerberosBinarySecurityToken in the incoming WSSecurity // header. You can do this by doing a DOM search WSSecurity = ... KerberosBinarySecurityToken kbst = ... // Now extract the AP_REQ from the BST and call acceptSecContext byte ap_req[] = kbst.getValue(); gssContext.acceptSecContext(ap_req); // The context is now extablished. (Note Mutual authentication would // need one more round trip) // Now extract the session key // KerberosUtils.getSession is an overloaded method, and this // particular one is meant to be used by server. Internally // it decrypts the ap_req packet using the server's key (or the // tgtSession key) and extracts the key from the decrypted ap_req // packet Subject srvrSubject = ... SecretKey sessionKey = KerberosUtils.getSessionKey(srvrSubject, ap_req);
Now you can decrypt or verify using this key.
9.2.3.5 Creating a SAML Assertion Token
Refer to Oracle XML Security for information on how to create Assertion
objects. From the Assertion
object you can create a SAML assertion token by simply invoking the SAMLAssertionToken(Assertion assertion)
constructor.
9.2.4 Security Token References (STR)
The WS Security specifications defines the concept of Security Token Reference (STR), which is a mechanism to refer to a security token. A Signature
or Encryption
uses this STR mechanism to identify the key that was used to sign or encrypt. STR supports mechanisms such as Direct Reference, Key Identifier, and Embedded.
STR typically supports the following mechanisms:
-
Direct Reference: The STR uses a URI to refer to the ST.
-
Key Identifier: The STR does not use a URI, but instead uses some other mechanism to identify the token, such as the
Issuer
serial for X509 tokens and the assertion ID for SAML tokens. The token may not be in the message at all. -
Embedded: The token is directly embedded in the
KeyInfo
.
9.2.4.1 Creating a direct reference STR
STRs are created using a uniform procedure; the mechanism to pass in the STR depends on the type of token.
To create the STR:
- Create the token as mentioned earlier.
- Call
.setWsuId()
to set an ID on that token - Create the STR with the ID from Step 2
- Pass in that STR in the
WSSSignatureParams
orWSEncryptionParams
Subsequent sections demonstrate how to pass in the STR for various tokens.
9.2.4.2 Creating a Reference STR for a username token
This example shows how to create a reference STR for a username token:
WSSecurity ws = ... WSSecurityTokenReference str = ws.createSTR_Username_ref("#MyUser");
9.2.4.3 Creating a Reference STR for a X509 Token
This example shows how to create a reference STR for an X509 token:
WSSecurity ws = ... WSSecurityTokenReference str = ws.createSTR_X509_Ref("#MyCert");
9.2.4.4 Creating a Reference STR for Kerberos Token
This example shows how to create a reference STR for a kerberos token:
WSSecurity ws = ... // use the appropriate value type String valueType = WSSURI.vt_GSSKerberosv5; WSSecurityTokenReference str = ws.createSTR_KerberosKeyRef ( "#MyToken");
9.2.4.5 Creating a Reference STR for a SAML Assertion token
This example shows how to create a reference STR for a SAML assertion token:
WSSecurity ws = ... WSSecurityTokenReference str = ws.createSTR_SAML_Assertion_Ref20("MySAMLAssertion")
9.2.4.6 Creating a Reference STR for an EncryptedKey
This example shows how to create a reference STR for an encrypted key:
WSSecurity ws = ... WSSecurityTokenReference str = ws.createSTR_EncKeyRef("MyEncKey")
9.2.4.7 Creating a Reference STR for a generic token
Instead of using the createSTR
methods you can also create the reference directly with the appropriate valueType
and tokenType
:
WSSecurity ws = ... String uri = "#MyToken"; WSSReference ref = new WSSReference(doc, uri); ref.setValueType(valueType); // set an optional valueType WSSecurityTokenReference str = new WSSecurityTokenReference(doc); str.setTokenType(tokenType); // set an optional tokenType str.appendChild(ref);
9.2.4.8 Creating a Key Identifier STR
A KeyIdentifier
is another way to refer to a security token that uses some intrinsic property of the token; for example, an assertionID
for a SAML Token
or a Subject Key Identifier
for an X509 token.
KeyIdentifers
are often used when the token itself is not present in the document. For example, an incoming message can be encrypted with a X509Cert
, but instead of having that X509Cert
in the message, it can have only a hint to it, in the form of a SubjectKeyIdentifier
.
9.2.4.9 Creating a KeyIdentifier STR for an X509 Token
There are three different ways to identify an X509 Token:
- Issuer Serial: A combination of Issuer DN and Serial number of the certificate
- Subject Key Identifier : The subject key Identifier of the certificate
- Thumbprint SHA1: SHA1 of the certificate.
X509Certificate cert = ... WSSecurity ws = ... WSSecurityTokenReference str = ws.createSTR_X509_IssuerSerial(cert); // alternatively use ws.createSTR_X509_SKI(cert) // or ws. createSTR_X509_ThumbprintSHA1(cert)
9.2.4.10 Creating a KeyIdentifier STR for a Kerberos Token
Kerberos tokens can be identified by the SHA1 of the AP_REQ packet or of the GSS wrapped AP_REQ packet.
byte ap_req[] = ... WSSecurity ws = ... String valueType = WSSURI.vt_GSSKerberosv5; WSSecurityTokenReference str = ws.createSTR_KerberosKeyIdSHA1(ap_req, valueType);
9.2.4.11 Creating a KeyIdentifier STR for a SAML Assertion Token
SAML assertions can be identified by the Assertion ID.
For local SAML 1.1 assertions use:
WSSecurity.createSTR_SAML_AssertionIdv11(byte assertionId[])
For remote SAML 1.1 assertions use:
createSTR_SAML_AssertionIdv11( byte assertionId[], AuthorityBinding authorityBinding)
For local SAML 2.0 assertions use:
createSTR_SAML_AssertionIdv20(byte assertionId[])
For remote SAML 2.0 assertions use a reference URI:
createSTR_SAML_Assertion_Ref20("MySAMLAssertion")
9.2.4.12 Creating a KeyIdentifier STR for an EncryptedKey
Remote encrypted keys can be identified by their SHA1 hash. Use this function to create the KeyIdentifier
:
createSTR_EncKeySHA1(byte sha1[])
9.2.4.13 Adding an STRTransform
An STRTransform is a very useful transform that you add to your signatures. This transform causes a temporary replacement of the STRs wth the corresponding STs while calculating the signature.
For example, you might include an X509 SKI based STR in your reference. Without the STRTransform
this will result in only the STR reference being included in the signature,that is, only the SKI value. But if you add an STRTransform
, during the signing and verifiing process the STR will be replaced by the actual X509 Certificate, that is, the entire X509 certificate will be included in the message.
9.2.5 Signing and Verifying
You can sign and verify SOAP messages, and confirm signatures.
This section contains a discussion of signing and verifying data.
Topics include:
9.2.5.1 Signing SOAP Messages
Take these steps to sign a SOAP message:
- Decide how you want to identify the data to be signed – the most common mechanism is to use an ID, but instead of an ID you can also use an XPath expression
- Decide on additional transforms – exclusive c14n and STR transforms are two common transforms that you might add.
- Decide on the signing key – you can either do HMAC signing with a symmetric key or do RSA/DSA signatures.
- Decide on how to indicate this signing key to the receiver – for this you usually need to create an STR as mentioned earlier.
9.2.5.1.1 Adding IDs to elements
IDs may be added to DOM elements.
Use the function:
WSSUtils.addWsuIdToElement(String id, Element element)
to add a wsu:Id
to the element to be signed. You can use this mechanism to add an ID to regular DOM element, or SAAJ objects which also derive from DOM Elements.
You must declare the wsu namespace prefix. For example, you can declare it at the SOAP Envelope level like this
SOAPEnvelope env = ... env.addNamespaceDeclaration("wsu" , WSSURI.ns_wsu);
To sign attachments, you must assign a ContentId
to each attachment. For this you need to use the following method:
setContentId(String contentId)
of the SAAJ AttachmentPart object.
9.2.5.1.2 Creating the WSSignatureParams object
A WSSSignatureParams
object must be created with all the signing parameters.
Use the following constructor to create the initial WSSignatureParams
object. If you want to use HMAC signing, pass in a value for hmacKey
, and null for the signingKey
; to use asymmetric signing, pass in a value for the signingKey
and null for hmacKey
.
WSSignatureParams(byte[] hmacKey, PrivateKey signingKey);
This constructor assumes c14nMethod=excC14N
, digestMethod=SHA1
and signMethod=hmacSHA/rsaSHA1/dsaSHA1
(depending on the key). If you want different algorithms use the following setters to set them:
setDigestMethod(String digestMethod) setSignMethod(String signMethod) setC14nMethod(String method)
You also need to set the STR that you have created earlier into this object; use the setKeyInfoData
for setting the STR.
setKeyInfoData(KeyInfoData keyInfoData)
When signing attachments, you need to set the SOAPMessage
into this WSSignatureParams
object so that it can resolve the cid references by locating corresponding attachments.
setSOAPMessage(SOAPMessage msg)
9.2.5.1.3 Specifying Transforms
There are two ways to specify transforms - a simpler but limited way, and an advanced and flexible way.
For the simple way, you need to set the following parameters in the WSSignatureParams:
setAttachmentContentOnly(boolean)
In the simple mode, all cid
references automatically get the AttachmentContentOnly
transform, but if you call setAttachmentContentOnly(false)
then the cid
references will get an AttachmentComplete
transform
· setUsingSTRTransform(boolean)
If you set this to true, each reference will be checked whether it points to an STR, if it does an STRTransform
will we added to that reference. Note the STRTransform
is only added if the reference directly points to an STR, not if the reference points to a an ancestor of an STR.
· setC14Nmethod(String)
This parameter defaults to exclusive c14n
, and specifies both the canonicalization method for each of the references and the canonicalization method for the SignedInfo
section.
· setUsingDecryptTransfom(boolean)
Set this to true
if you want a decrypt transform to be added.
9.2.5.1.4 Calling the WSSecurity.sign method
The final step is to call the following method in WSSecurity to perform the actual signing.
XSSignature sign (String[] uris, WSSignatureParams sigParams, XSAlgorithmIdentifier[][] trans)
This method creates the <Signature>
element, computes digests of each reference and finally computes the signature.
uris is an array of IDs to be signed. A separate <Reference>
will be created for each element of this array.
As described earlier there are two ways to specify the transforms – a simple way in which the transform must be null
, and the transformation information is specified throught the various set methods mentioned above (in WSSignatureParams
). Or a more advanced way where the transform parameter must explicitly specify all the transforms for each reference, that is, trans.length
must be equal to uris.length
.
9.2.5.2 Verifying SOAP Messages
When verifying a signature you first need to locate the signature elements in the <wsse:Security>
header; for this you can use the method
WSSecurity ws = ... List<XSSignature>sigs = ws.getSignatures();
This method searches the DOM tree to find all immediate children of <wsse:Security>
that are <dsig:Signature>
and then creates XSSignature
wrapper objects for each of those elements and returns them. (Note the namespace prefixes do not have to use wsse and dsig).
If you already have the verification key in hand, you can call the following method - either pass in an hmacKey
for HMAC signatures or a signingKey
for asymmetric key signatures. The SOAPMessage
is only need when attachments are signed.
XSSignature sig = sigs[0]; byte [] hmacKey = ... PublicKey signingKey = ... ; // Need either hmacKey of signingKey SOAPMessage msg = null; // needed only for attachments boolean res = WSSecurity.verify(sig, byte[] hmacKey, signingKey, msg);
However, if you do not have the verification key, you need to set up the following callbacks for resolving STR Key Identifiers. Recall that STR Key Identifiers are usually references to tokens outside the document, so Oracle Security Developer Tools cannot locate these tokens unless you explicitly set up these callbacks.
Table 9-3 Callbacks to Resolve STR Key Identifiers
Token Type | Implementation Interface and Registration | Notes |
---|---|---|
Username Token |
Interface: PasswordRetriever
Registration: UsernameToken.addPasswordRetriever |
This callback resolves the UsernameToken Reference STRs. In the getPassword() callback, return the password corresponding to the user. This secret key will be derived from password, iteration count and salt. login() and logout() callbacks are not used |
Username Token |
Interface: KeyDerivator Registration: UsernameToken.addKeyDerivator |
This callback also resolves the UsernameToken Reference STRs. Use it when you want to use your own key derivation algorithm. In the resolve() callback, derive the key and return it. |
X509 |
Interface: X509KeyIdentifierResolver Registration: X509KeyIdentifier.addResolver |
This callback resolves Thumbprint and SKI Key Identifier STRs. Implement the resolve() and getPrivateKey() callbacks to return the certificate and the private key respectively. Note: The private key is not required for verification, but it is required for decryption. If you have an array of certificates, use the X509KeyIdentifier.matches() method to match each cerificate against the passed-in X509 KeyIdentifier. |
X509 |
Interface: X509IssuerSerialResolver Registration: X509IssuerSerial.addResolver |
This callback resolves Issuer Serial Key Identifier STRs. Implement the resolve() and getPrivateKey() callbacks as in the previous case. |
Kerberos |
Interface: KerberosKeyIdentifierResolver
Registration: KerberosKeyIdentifier.addResolver |
This callback resolves Kerberos STRs. Implement the resolve() and resolveKey() method to return the ap_req packet and the session key/subkey which corresponds to the SHA1 value present in the KeyIdentifier.
If you have an array of ap_req packets, calculate the SHA1 of each one of them, and find the one whose SHA1 matches the value returned by KerberosKeyIdentifier.getValue(). Return this ap_req packet in the resolve() method.
For the resolveKey() method you need to take one more step and return they key present inside the ap_Req packet, for this youe can use the KerberosUtils.getSessionKey(Subject, byte[]) method, which decrypts the ap_req packet using the Subject's key and extracts the session key/sub-key from it. |
SAML Assertion v1.1 |
Interface: SAMLAssertionKeyIdentifierResolver Registration: SAMLAssertionKeyIdentifier.addResolver |
This callback resolves SAML Assertion KeyIdentifier STRs. Implement the resolve(), getPublicKey() and getPrivateKey() methods to return the SAML assertion, SAMLX509Cert, and private key respectively. (Note: The private key is required only for decryption, not for verification.) |
SAML Assertion v 2.0 |
Interface: SAML2AssertionKeyIdentifierResolver Registration: SAML2AssertionKeyIdentifier.addResolver |
See previous notes for SAML Assertion v1.1. |
For tokens that use symmetric keys - UserName Token, Kerberos, and EncryptedKey - you need to set up a resolver, because the document does not have this symmetric key, and Oracle Security Developer Tools cannot verify (or decrypt) unless you set the resolvers.
For tokens that use asymmetric keys - SAML Assertions and X509 Tokens - you do not need to set up a resolver if it uses a direct URI reference STR or an embedded token, because in these cases Oracle Security Developer Tools can locate the certificate on its own. However you still need to set up the CertificateValidator
callback because Oracle Security Developer Tools will not blindly use a certificate in the message unless you have validated the certificate in your callback.
See Also:
After you have set up all the resolvers and the CertificateValidator
, use the following method:
SOAPMessage msg = null; // needed only for attachments boolean searchTokens = true; boolean res = WSSecurity.verify(sig, searchTokens, msg);
This method inspects the Signature's KeyInfo
and either searches for the certificate, or calls the appropriate resolvers to get the signing key.
You can also use the WSSecurity.verifyAll
method which searches for signatures and verifies them one by one.
9.2.5.3 Confirming Signatures
You use the WSSignatureConfirmation
wrapper class to contruct and process signature confirmation elements.
9.2.5.3.1 Signature Confirmation Response Generation
For response generation use the following function in WSSecurity:
List<WSSignatureConfirmation> createSignatureConfirmations(Document doc);
This looks at all the Signatures
present in the current WSSecurity
element, and constructs corresponding SignatureConfirmation
elements in a new document. These could be put in the response's WSSecuirty header.
9.2.5.3.2 Signature Confirmation Response Processing
For response processing, first use this function (at request time) to save all the Signature values.
String [] getSignatureValues()
At response processing time, you can then use this saved list to compare against the incoming SignatureConfirmations
as follows:
boolean verifySignatureConfirmations(String sigValue[])
9.2.6 Encrypting and Decrypting
You can encrypt or decrypt SOAP messages with or without an EncryptedKey
.
There are two primary encryption methods:
- With
EncryptedKey
: Encrypt the elements with a random session key, then encrypt this session key into an<EncryptedKey>
element and place that element in the<wsse:Security>
header. - Without
EncryptedKey
: Encrypt the elements with known symmetric keys, which may be different for each element; construct a<ReferenceList>
element with references to each of these encrypted data sections, and place the<ReferenceList>
in the<wsse:Security>
header.
Note:
While encrypting regular DOM elements is standard practice, you can also encrypt SOAP headers, the SOAP body, and attachments. Special considerations apply for encrypting these objects as explained later.
9.2.6.1 Encrypting SOAP messages with EncryptedKey
You can encrypt SOAP messages by means of EncryptedKey
.
First decide on a key to use to encrypt this random session key, then create an STR with the information that the receiver will use to locate this decryption key:
Key keyEncKey = ... ; WSSecurityTokenReference str = ...
create a WSSEncryptionParams
with this information:
// Choose a data encryption algorithm - say AES 128 String dataEncAlg = XMLURI.alg_aes128_CBC; // Either generate a random session key yourself, or set this to // null to indicate that OSDT should generate it SecretKey dataEncKey = null; // Depending on the KeyEncryptionKey that you have chosen choose // either an RSA key wrap or a symmetric key wrap String keyEncAlg = XMLURI.alg_rsaOAEP_MGF1; // Now put all this information into a WSSEncryptionParams WSSEncryptionParams eParam = new WSSEncryptionParams( dataEncAlg, dataEncKey, keyEncAlg, keyEncKey, str);
regular DOM element, SOAP headers, the SOAP Body or AttachmentParts:
Element elem1 = ... // one object to be encrypted Element elem2 = … // another object to be encrypted ArrayList objectList[] = new ArrayList(); objectList.add(elem1); objectList.add(elem2);
Create two more arrays to indicate whether each object is to be encrypted content only, and what IDs will be assigned to the resulting EncryptedData
objects:
Note:
SOAP bodies are always encrypted content only, regardless of what you pass in this flag. For attachments, "not content only" means content plus mime headers.
// both these elements are not content only boolean[] contentOnlys = { false, false }; // After encryption the EncryptedData elements will get these ids String encDataIds[] = { "id1", "id2" };
Finally, call the encryptWithEncKey
method:
WSSecurity ws = ... XEEncryptedKey encKey = ws.encryptWithEncKey(objectList, contentOnlys, encDataIds, eParam);
9.2.6.2 Encrypting SOAP messages without EncryptedKey
Use these steps if you do not wish to use an EncryptedKey
:
Decide on a data encryption key; you can either use the same one for all the EncryptedData sections or a different one for each. Also create an STR with the information that the receiver will use to locate this decryption key, and put into a WSSEncryptionParams
object:
SecretKey dataEncKey = ... ; // assuming 128 bit AES key String dataEncAlg = XMLURI.alg_aes128_CBC; WSSecurityTokenReference str = ... // Now put all this information into a WSSEncryptionParams WSSEncryptionParams eParam = new WSSEncryptionParams( dataEncAlg, dataEncKey, null, null, str);
Now create a list of elements to be encrypted as before, along with the associated contentOnly
and encDataIds
array:
Element elem1 = ... // one object to be encrypted Element elem2 = … // another object to be encrypted ArrayList objectList[] = new ArrayList(); objectList.add(elem1); objectList.add(elem2); // both these elements are not content only boolean[] contentOnlys = { false, false }; // After encryption the EncryptedData elements will get these ids String encDataIds[] = { "id1", "id2" };
Finally, call the encryptWithNoEncKey
method:
WSSecurity ws = ... XEEncryptedKey encKey = ws.encryptWithNoEncKey(objectList, contentOnlys, encDataIds, new WSEncryptionParams[]{eParam, eParam});
In this example we used the same encryptionParams
for both elements.
9.2.6.3 Encrypting SOAP Headers into an EncryptedHeader
When you call the encrypt methods on the SOAP header block , with content only set to false
, the entire SOAP header block is encrypted into an EncryptedData
element; this element is placed inside an EncryptedHeader
element, which replaces the original SOAP header block.
The mustUnderstand
and actor
attributes are copied over from the current wsse:Security
header.
9.2.6.4 Decrypting SOAP messages with EncryptedKey
To decrypt SOAP messages with EncryptedKey
, use:
WSSecurity.decrypt(XEEncryptedKey, PrivateKey, SOAPMessage)
which first decrypts the EncryptedKey
with the given PrivateKey
to obtain a symmetric key, then uses this symmetric key to decrypt all the references inside the EncrytedKey
.
If you do not know the PrivateKey
, call:
decrypt(XEEncryptedKey, SOAPMessage)
which looks into the KeyInfo
of the EncryptedKey
and calls the registered callbacks to obtain the private key.
If you already know the decrypted form of the EncryptedKey
then use:
decrypt(XEEncryptedKey, SecretKey, SOAPMessage)
which uses the given symmetric key to decrypt all the references inside the EncryptedKey
.
9.2.6.5 Decrypting SOAP messages without EncryptedKey
When you wish to decrypt all the elements (or attachments) mentioned in a top level ReferenceList
, use:
decrypt(XEReferenceList, SecretKey, SOAPMessage)
which uses the given symmetric key to decrypt all the references inside the ReferenceList
. This functions assumes that all the references are encrypted with the same key.
If you do not know the SecretKey
, or if all the references are not encrypted with the same key, send in a null
for the SecretKey
; decrypt
then looks into the KeyInfo
of each of the EncrytedData
and calls the registered callbacks to obtain the symmetric key.
9.3 Additional Resources for Web Services Security
OASIS Specifications, such as OASIS WSS SOAP Message Security Specification and OASIS WSS Username Token Profile Specification, provide more information about Web Services Security.
The following resources provide more information about Web Services Security:
-
OASIS WSS SOAP Message Security Specification
-
OASIS WSS Username Token Profile Specification
-
OASIS WSS X.509 Certificate Token Profile Specification
-
OASIS WSS SAML Assertion Token Profile Specification
-
OASIS WSS SWA Token Profile Specification 1.1
See Also:
Links to these documents are available in References.
9.4 The Oracle Web Services Security Java API Reference
The Oracle Fusion Middleware Java API Reference for Oracle Security Developer Tools guide explains the classes, interfaces, and methods available in the Oracle Web Services Security API.
You can access the guide at:
Oracle Fusion Middleware Java API Reference for Oracle Security Developer Tools