Oracle® Fusion Middleware Reference for Oracle Security Developer Tools 11g Release 1 (11.1.1) E10037-01 |
|
![]() Previous |
![]() Next |
Oracle Web Services Security provides a complete implementation of the OASIS WS Security 1.1 standard. This chapter describes how to install and use the SDK.
This chapter contains these topics:
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
The Oracle Security Developer Tools are installed with Oracle Application Server in ORACLE_HOME/modules/oracle.osdt_11.1.1.
To use Oracle Web Services Security, you must have Development Kit (JDK) version 5 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.
This section describes classes and interfaces in the Oracle Web Services Security API. It contains these topics:
Oracle Web Services Security makes use of the concept of element wrappers.
Table 10-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 Section 8.7, "About Element Wrappers in the Oracle Security Developer Tools 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.
The WS Security specification defines a new SOAP Header called <wsse:Security>. All security information is to be stored inside this header, namely:
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, a UserName
token inside the Security
header, and a Timestamp
token in the Security
header.
EncryptedKeys - Any encrypted session keys are stored here.
ReferenceList - Contains a list of all the EncryptedData
sections.
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(...);
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 = ...
The WS Security specification defines the concept of "security tokens", sometimes abbreviated to ST.
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. 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 10-2 Security Tokens for Oracle Web Services Security
Type of Token (Java Class) | Variations | Keys |
---|---|---|
Username tokenoracle.security.xmlsec.wss.username. UsernameToken |
|
Symmetric key obtained by running KeyDerivation on user's password |
X509 certificateoracle.security.xmlsec.wss.x509. X509BinarySecurityToken |
|
|
Kerberos ticketoracle.security.xmlsec.wss.kerberos. KerberosBinarySecurityToken |
|
Either the session key present in the ticket, or a subkey. |
SAML Assertion 1.1oracle.security.xmlsec.wss.saml.SAMLAssertionToken SAML Assertion 2.0oracle.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. |
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.
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.
Kerberos tokens are used, as a rule, in conjunction with the Java GSS-API.
Client Side
//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
// 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.
Refer to Chapter 8, "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.
The WS Security specification also defines the concept of a "Security token reference", (sometimes abbreviated to 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 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
.
Before creating the STR, first create the token as mentioned earlier, then call .setWsuId()
to set an ID on that token. Next create the STR with that ID, and finally pass in that STR in the WSSSignatureParams
or WSEncryptionParams
as described below.
WSSecurity ws = ... WSSecurityTokenReference str = ws.createSTR_Username_ref("#MyUser");
WSSecurity ws = ... WSSecurityTokenReference str = ws.createSTR_X509_Ref("#MyCert");
WSSecurity ws = ... // use the appropriate value type String valueType = WSSURI.vt_GSSKerberosv5; WSSecurityTokenReference str = ws.createSTR_KerberosKeyRef ( "#MyToken");
WSSecurity ws = ... WSSecurityTokenReference str = ws.createSTR_SAML_Assertion_Ref20("MySAMLAssertion")
WSSecurity ws = ... WSSecurityTokenReference str = ws.createSTR_EncKeyRef("MyEncKey")
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);
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
.
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)
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);
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")
Remote encrypted keys can be identified by their SHA1 hash. Use this function to create the KeyIdentifier
:
createSTR_EncKeySHA1(byte sha1[])
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.
This section contains a discussion of topics on signing and verifying data.
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 symmteric key or do RSA/DSA signatures.
Decide on how to indicate this signing key to the reciever – for this you usually need to create an STR as mentioned earlier.
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.
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)
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.
Finally 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
.
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 10-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 |
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. |
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.
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.
You use the WSSignatureConfirmation
wrapper class to contruct and process signature confirmation elements.
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.
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[])
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. |
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);
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.
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.
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
.
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.
The Oracle Web Services Security API Reference (Javadoc) is available at:
Oracle Fusion Middleware Web Services Security Java API Reference for Oracle Security Developer Tools
For example programs using the Oracle Security Developer Tools, see the Oracle Technology Network Web Site at http://www.oracle.com/technology/sample_code/products/id_mgmt/index.html
.