blob: 8c5e46c9c41f1d8a1cda39b2782563d42fa686e8 [file] [log] [blame]
/*
* Copyright 2003-2004 The Apache Software Foundation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.ws.security;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.ws.security.components.crypto.Crypto;
import org.apache.ws.security.message.EnvelopeIdResolver;
import org.apache.ws.security.message.token.BinarySecurity;
import org.apache.ws.security.message.token.PKIPathSecurity;
import org.apache.ws.security.message.token.SecurityTokenReference;
import org.apache.ws.security.message.token.Timestamp;
import org.apache.ws.security.message.token.UsernameToken;
import org.apache.ws.security.message.token.X509Security;
import org.apache.ws.security.transform.STRTransform;
import org.apache.ws.security.util.WSSecurityUtil;
import org.apache.ws.security.util.XmlSchemaDateFormat;
import org.apache.ws.security.util.Base64;
import org.apache.xml.security.encryption.XMLCipher;
import org.apache.xml.security.encryption.XMLEncryptionException;
import org.apache.xml.security.exceptions.XMLSecurityException;
import org.apache.xml.security.keys.KeyInfo;
import org.apache.xml.security.keys.content.X509Data;
import org.apache.xml.security.keys.content.x509.XMLX509Certificate;
import org.apache.xml.security.signature.Reference;
import org.apache.xml.security.signature.SignedInfo;
import org.apache.xml.security.signature.XMLSignature;
import org.apache.xml.security.signature.XMLSignatureException;
import org.apache.xml.security.transforms.Transform;
import org.opensaml.SAMLAssertion;
import org.opensaml.SAMLException;
import org.opensaml.SAMLObject;
import org.opensaml.SAMLSubject;
import org.opensaml.SAMLSubjectStatement;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.Text;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.SecretKey;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.UnsupportedCallbackException;
import javax.xml.namespace.QName;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.security.Principal;
import java.security.PrivateKey;
import java.security.cert.CertificateExpiredException;
import java.security.cert.CertificateNotYetValidException;
import java.security.cert.X509Certificate;
import java.text.DateFormat;
import java.util.Calendar;
import java.util.Iterator;
import java.util.Vector;
/**
* WS-Security Engine.
* <p/>
*
* @author Davanum Srinivas (dims@yahoo.com).
* @author Werner Dittmann (Werner.Dittmann@t-online.de).
*/
public class WSSecurityEngine {
private static final String VALUE_TYPE = "ValueType";
private static Log log = LogFactory.getLog(WSSecurityEngine.class.getName());
private static Log tlog =
LogFactory.getLog("org.apache.ws.security.TIME");
private static final Class[] constructorType = {WSSConfig.class, org.w3c.dom.Element.class};
private static WSSecurityEngine engine = null;
/**
* The symmetric key.
*/
private byte[] decryptedBytes = null;
private boolean doDebug = false;
protected WSSConfig wssConfig = WSSConfig.getDefaultWSConfig();
/**
* <code>wsse:BinarySecurityToken</code> as defined by WS Security specification
*/
protected QName binaryToken;
/**
* <code>wsse:UsernameToken</code> as defined by WS Security specification
*/
protected QName usernameToken;
/**
* <code>wsu:Timestamp</code> as defined by OASIS WS Security specification,
*/
protected QName timeStamp;
/**
* <code>ds:Signature</code> as defined by XML Signature specification,
* enhanced by WS Security specification
*/
protected static final QName SIGNATURE = new QName(WSConstants.SIG_NS, WSConstants.SIG_LN);
/**
* <code>xenc:EncryptedKey</code> as defined by XML Encryption specification,
* enhanced by WS Security specification
*/
protected static final QName ENCRYPTED_KEY = new QName(WSConstants.ENC_NS, WSConstants.ENC_KEY_LN);
/**
* <code>xenc:ReferenceList</code> as defined by XML Encryption specification,
*/
protected static final QName REFERENCE_LIST = new QName(WSConstants.ENC_NS, WSConstants.REF_LIST_LN);
/**
* <code>saml:Assertion</code> as defined by SAML specification
*/
protected static final QName SAML_TOKEN = new QName(WSConstants.SAML_NS, WSConstants.ASSERTION_LN);
static {
}
public WSSecurityEngine() {
this(WSSConfig.getDefaultWSConfig());
}
public WSSecurityEngine(WSSConfig wssConfig) {
this.wssConfig = wssConfig;
binaryToken = new QName(wssConfig.getWsseNS(), WSConstants.BINARY_TOKEN_LN);
usernameToken = new QName(wssConfig.getWsseNS(), WSConstants.USERNAME_TOKEN_LN);
timeStamp = new QName(wssConfig.getWsuNS(), WSConstants.TIMESTAMP_TOKEN_LN);
}
/**
* Get a singleton instance of security engine.
* <p/>
*
* @return ws-security engine.
*/
public synchronized static WSSecurityEngine getInstance() {
if (engine == null) {
engine = new WSSecurityEngine();
}
return engine;
}
/**
* Get a singleton instance of security engine with specified configuration
* settings. <p/>
*
* @param wssConfig
* the configuration parameters to use.
* @return ws-security engine.
*/
public synchronized static WSSecurityEngine getInstance(WSSConfig wssConfig) {
if (engine == null) {
engine = new WSSecurityEngine(wssConfig);
}
return engine;
}
/**
* Process the security header given the soap envelope as W3C document.
* <p/>
* This is the main entry point to verify or decrypt a SOAP enevelope.
* First check if a <code>wsse:Security</code> is availabe with the
* defined actor.
*
* @param doc the SOAP envelope as {@link Document}
* @param actor the engine works on behalf of this <code>actor</code>. Refer
* to the SOAP specification about <code>actor</code> or <code>role
* </code>
* @param cb a callback hander to the caller to resolve passwords during
* encryption and {@link UsernameToken} handling
* @param crypto the object that implements the access to the keystore and the
* handling of certificates.
* @return a result vector
* @throws WSSecurityException
* @see WSSecurityEngine#processSecurityHeader(Element securityHeader, CallbackHandler cb,Crypto sigCrypto, Crypto decCrypto)
*/
public Vector processSecurityHeader(Document doc,
String actor,
CallbackHandler cb,
Crypto crypto)
throws WSSecurityException {
return processSecurityHeader(doc, actor, cb, crypto, crypto);
}
/**
* Process the security header given the soap envelope as W3C document.
* <p/>
* This is the main entry point to verify or decrypt a SOAP enevelope.
* First check if a <code>wsse:Security</code> is availabe with the
* defined actor.
*
* @param doc the SOAP envelope as {@link Document}
* @param actor the engine works on behalf of this <code>actor</code>. Refer
* to the SOAP specification about <code>actor</code> or <code>role
* </code>
* @param cb a callback hander to the caller to resolve passwords during
* encryption and {@link UsernameToken} handling
* @param sigCrypto the object that implements the access to the keystore and the
* handling of certificates for Signature
* @param decCrypto the object that implements the access to the keystore and the
* handling of certificates for Decryption
* @return a result vector
* @throws WSSecurityException
* @see WSSecurityEngine#processSecurityHeader(Element securityHeader, CallbackHandler cb,Crypto sigCrypto, Crypto decCrypto)
*/
public Vector processSecurityHeader(Document doc,
String actor,
CallbackHandler cb,
Crypto sigCrypto,
Crypto decCrypto)
throws WSSecurityException {
doDebug = log.isDebugEnabled();
if (doDebug) {
log.debug("enter processSecurityHeader()");
}
if (actor == null) {
actor = "";
}
Vector wsResult = null;
SOAPConstants sc = WSSecurityUtil.getSOAPConstants(doc.getDocumentElement());
Element elem = WSSecurityUtil.getSecurityHeader(wssConfig, doc, actor, sc);
if (elem != null) {
if (doDebug) {
log.debug("Processing WS-Security header for '" + actor
+ "' actor.");
}
wsResult = processSecurityHeader(elem, cb, sigCrypto, decCrypto);
}
return wsResult;
}
/**
* Process the security header given the <code>wsse:Security</code> DOM
* Element. <p/>This function loops over all direct child elements of the
* <code>wsse:Security</code> header. If it finds a knwon element, it
* transfers control to the appropriate handling function. The mehtod
* processes the known child elements in the same order as they appear in
* the <code>wsse:Security</code> element. This is in accordance to the WS
* Security specification. <p/>Currently the functions can handle the
* following child elements: here:
* <ul>
* <li>{@link #SIGNATURE <code>ds:Signature</code>}</li>
* <li>{@link #ENCRYPTED_KEY <code>xenc:EncryptedKey</code>}</li>
* <li>{@link #USERNAME_TOKEN <code>wsse:UsernameToken</code>}</li>
* </ul>
* <p/>
*
* @param securityHeader the <code>wsse:Security</code> header element
* @param cb a callback hander to the caller to resolve passwords during
* encryption and {@link UsernameToken}handling
* @param sigCrypto the object that implements the access to the keystore and the
* handling of certificates used for Signature
* @param decCrypto the object that implements the access to the keystore and the
* handling of certificates used for Decryption
* @return a Vector of {@link WSSecurityEngineResult}. Each element in the
* the Vector represents the result of a security action. The elements
* are ordered according to the sequence of the security actions in the
* wsse:Signature header. The Vector maybe empty if no security processing
* was performed.
* @throws WSSecurityException
*/
protected Vector processSecurityHeader(Element securityHeader,
CallbackHandler cb,
Crypto sigCrypto,
Crypto decCrypto) throws WSSecurityException {
long t0 = 0, t1 = 0, t2 = 0;
if (tlog.isDebugEnabled()) {
t0 = System.currentTimeMillis();
}
/*
* Gather some info about the document to process and store
* it for retrival. Store the implemenation of signature crypto
* (no need for encryption --- yet)
*/
WSDocInfo wsDocInfo = new WSDocInfo(securityHeader.getOwnerDocument().hashCode());
wsDocInfo.setCrypto(sigCrypto);
NodeList list = securityHeader.getChildNodes();
int len = list.getLength();
Node elem;
Principal lastPrincipalFound = null;
if (tlog.isDebugEnabled()) {
t1 = System.currentTimeMillis();
}
Vector returnResults = new Vector();
for (int i = 0; i < len; i++) {
elem = list.item(i);
if (elem.getNodeType() != Node.ELEMENT_NODE) {
continue;
}
QName el = new QName(elem.getNamespaceURI(), elem.getLocalName());
if (el.equals(SIGNATURE)) {
if (doDebug) {
log.debug("Found signature element");
}
WSDocInfoStore.store(wsDocInfo);
X509Certificate[] returnCert = new X509Certificate[1];
Vector returnQname[] = new Vector[1];
try {
lastPrincipalFound = verifyXMLSignature((Element) elem,
sigCrypto, returnCert, returnQname);
} catch (WSSecurityException ex) {
throw ex;
} finally {
WSDocInfoStore.delete(wsDocInfo);
}
if (lastPrincipalFound instanceof WSUsernameTokenPrincipal) {
returnResults.add(0, new WSSecurityEngineResult(
WSConstants.UT_SIGN, lastPrincipalFound, null,
returnQname[0]));
} else {
returnResults.add(0, new WSSecurityEngineResult(
WSConstants.SIGN, lastPrincipalFound,
returnCert[0], returnQname[0]));
}
} else if (el.equals(ENCRYPTED_KEY)) {
if (doDebug) {
log.debug("Found encrypted key element");
}
if (decCrypto == null) {
throw new WSSecurityException(WSSecurityException.FAILURE,
"noDecCryptoFile");
}
if (cb == null) {
throw new WSSecurityException(WSSecurityException.FAILURE,
"noCallback");
}
handleEncryptedKey((Element) elem, cb, decCrypto);
returnResults.add(0, new WSSecurityEngineResult(WSConstants.ENCR, null, null, null));
} else if (el.equals(REFERENCE_LIST)) {
if (doDebug) {
log.debug("Found reference list element");
}
if (cb == null) {
throw new WSSecurityException(WSSecurityException.FAILURE,
"noCallback");
}
handleReferenceList((Element) elem, cb);
returnResults.add(0, new WSSecurityEngineResult(WSConstants.ENCR, null, null, null));
} else if (el.equals(usernameToken)) {
if (doDebug) {
log.debug("Found UsernameToken list element");
}
lastPrincipalFound = handleUsernameToken((Element) elem, cb);
returnResults.add(0, new WSSecurityEngineResult(WSConstants.UT,
lastPrincipalFound, null, null));
} else if (el.equals(SAML_TOKEN)) {
if (doDebug) {
log.debug("Found SAML Assertion element");
}
SAMLAssertion assertion = handleSAMLToken((Element) elem);
wsDocInfo.setAssertion((Element) elem);
returnResults.add(0,
new WSSecurityEngineResult(WSConstants.ST_UNSIGNED, assertion));
} else if (el.equals(timeStamp)) {
if (doDebug) {
log.debug("Found Timestamp list element");
}
/*
* Decode Timestamp, add the found time (created/expiry) to result
*/
Timestamp timestamp = new Timestamp(wssConfig, (Element) elem);
handleTimestamp(timestamp);
returnResults.add(0,
new WSSecurityEngineResult(WSConstants.TS,
timestamp));
} else {
/*
* Add check for a BinarySecurityToken, add info to WSDocInfo. If BST is
* found before a Signature token this would speed up (at least a little
* bit) the processing of STR Transform.
*/
if (doDebug) {
log.debug("Unknown Element: " + elem.getLocalName() + " " + elem.getNamespaceURI());
}
}
}
if (tlog.isDebugEnabled()) {
t2 = System.currentTimeMillis();
tlog.debug("processHeader: total= " + (t2 - t0) +
", prepare= " + (t1 - t0) +
", handle= " + (t2 - t1));
}
return returnResults;
}
/**
* Verify the WS-Security signature.
* <p/>
* The functions at first checks if then <code>KeyInfo</code> that is
* contained in the signature contains standard X509 data. If yes then
* get the certificate data via the standard <code>KeyInfo</code> methods.
* <p/>
* Otherwise, if the <code>KeyInfo</code> info does not contain X509 data, check
* if we can find a <code>wsse:SecurityTokenReference</code> element. If yes, the next
* step is to check how to get the certificate. Two methods are currently supported
* here:
* <ul>
* <li> A URI reference to a binary security token contained in the <code>wsse:Security
* </code> header. If the derefenced token is
* of the correct type the contained certificate is extracted.
* </li>
* <li> Issuer name an serial number of the certificate. In this case the method
* looks up the certificate in the keystore via the <code>crypto</code> parameter.
* </li>
* </ul>
* <p/>
* The methods checks is the certificate is valid and calls the
* {@link XMLSignature#checkSignatureValue(X509Certificate) verfication} function.
*
* @param elem the XMLSignature DOM Element.
* @param crypto the object that implements the access to the keystore and the
* handling of certificates.
* @param returnCert verifyXMLSignature stores the certificate in the first
* entry of this array. Ther caller may then further validate
* the certificate
* @param returnQname verifyXMLSignature store the Qnames of all signed elements
* in this Vector ordered according the sequence in the Signature
* header.
* @return the subject principal of the validated X509 certificate (the
* authenticated subject). The calling function may use this
* principal for further authentication or authorization.
* @throws WSSecurityException
*/
protected Principal verifyXMLSignature(Element elem,
Crypto crypto,
X509Certificate[] returnCert,
Vector[] returnQname)
throws WSSecurityException {
if (doDebug) {
log.debug("Verify XML Signature");
}
long t0 = 0, t1 = 0, t2 = 0;
if (tlog.isDebugEnabled()) {
t0 = System.currentTimeMillis();
}
XMLSignature sig = null;
try {
sig = new XMLSignature(elem, null);
} catch (XMLSecurityException e2) {
throw new WSSecurityException(WSSecurityException.FAILED_CHECK,
"noXMLSig");
}
sig.addResourceResolver(EnvelopeIdResolver.getInstance(wssConfig));
X509Certificate[] certs = null;
KeyInfo info = sig.getKeyInfo();
byte[] secretKey = null;
UsernameToken ut = null;
if (info != null) {
Node node;
if (wssConfig.getProcessNonCompliantMessages()) {
node = WSSecurityUtil.getDirectChildWSSE(info.getElement(),
SecurityTokenReference.SECURITY_TOKEN_REFERENCE);
} else {
node = WSSecurityUtil.getDirectChild(info.getElement(),
SecurityTokenReference.SECURITY_TOKEN_REFERENCE,
wssConfig.getWsseNS());
}
if (node == null) {
throw new WSSecurityException(
WSSecurityException.INVALID_SECURITY,
"unsupportedKeyInfo");
}
SecurityTokenReference secRef = new SecurityTokenReference(
wssConfig, (Element) node);
int docHash = elem.getOwnerDocument().hashCode();
/*
* Her we get some information about the document that is being
* processed, in partucular the crypto implementation, and already
* detected BST that may be used later during dereferencing.
*/
WSDocInfo wsDocInfo = WSDocInfoStore.lookup(docHash);
if (secRef.containsReference()) {
Element token = secRef.getTokenElement(elem.getOwnerDocument(),
wsDocInfo);
/*
* at this point check token type: UsernameToken, Binary, SAML
* Crypto required only for Binary and SAML
*/
QName el = new QName(token.getNamespaceURI(), token
.getLocalName());
if (token.getLocalName().equals(UsernameToken.TOKEN)) {
ut = new UsernameToken(wssConfig, token);
secretKey = ut.getSecretKey();
} else {
if (crypto == null) {
throw new WSSecurityException(WSSecurityException.FAILURE,
"noSigCryptoFile");
}
if (token.getLocalName().equals(binaryToken.getLocalPart())) {
certs = getCertificatesTokenReference((Element) token,
crypto);
} else if (el.equals(SAML_TOKEN)) {
certs = getCertificatesFromSAML((Element) token, crypto);
} else {
throw new WSSecurityException(
WSSecurityException.INVALID_SECURITY,
"unsupportedKeyInfo", new Object[] { el
.toString() });
}
}
} else if (secRef.containsX509IssuerSerial()) {
certs = secRef.getX509IssuerSerial(crypto);
} else if (secRef.containsKeyIdentifier()) {
certs = secRef.getKeyIdentifier(crypto);
} else {
throw new WSSecurityException(
WSSecurityException.INVALID_SECURITY,
"unsupportedKeyInfo", new Object[] { node.toString() });
}
} else {
if (crypto == null) {
throw new WSSecurityException(WSSecurityException.FAILURE,
"noSigCryptoFile");
}
if (crypto.getDefaultX509Alias() != null) {
certs = crypto.getCertificates(crypto.getDefaultX509Alias());
} else {
throw new WSSecurityException(
WSSecurityException.INVALID_SECURITY,
"unsupportedKeyInfo");
}
}
if (tlog.isDebugEnabled()) {
t1 = System.currentTimeMillis();
}
if ((certs == null || certs.length == 0 || certs[0] == null) && secretKey == null) {
throw new WSSecurityException(WSSecurityException.FAILED_CHECK);
}
if (certs != null) {
try {
certs[0].checkValidity();
} catch (CertificateExpiredException e) {
throw new WSSecurityException(WSSecurityException.FAILED_CHECK,
"invalidCert");
} catch (CertificateNotYetValidException e) {
throw new WSSecurityException(WSSecurityException.FAILED_CHECK,
"invalidCert");
}
}
try {
boolean signatureOk = false;
if (certs != null) {
signatureOk = sig.checkSignatureValue(certs[0]);
} else {
signatureOk = sig.checkSignatureValue(sig
.createSecretKey(secretKey));
}
if (signatureOk) {
if (tlog.isDebugEnabled()) {
t2 = System.currentTimeMillis();
tlog.debug("Verify: total= " + (t2 - t0)
+ ", prepare-cert= " + (t1 - t0) + ", verify= "
+ (t2 - t1));
}
/*
* Now dig into the Signature element to get the elements that
* this Signature covers. Build the QName of these Elements and
* return them to caller
*/
SignedInfo si = sig.getSignedInfo();
int numReferences = si.getLength();
Vector qvec = new Vector(numReferences);
for (int i = 0; i < numReferences; i++) {
Reference siRef;
try {
siRef = si.item(i);
} catch (XMLSecurityException e3) {
throw new WSSecurityException(
WSSecurityException.FAILED_CHECK);
}
String uri = siRef.getURI();
Element se = WSSecurityUtil.getElementByWsuId(wssConfig,
elem.getOwnerDocument(), uri);
if (se == null) {
se = WSSecurityUtil.getElementByGenId(elem
.getOwnerDocument(), uri);
}
if (se == null) {
throw new WSSecurityException(
WSSecurityException.FAILED_CHECK);
}
QName qn = new QName(se.getNamespaceURI(), se
.getLocalName());
qvec.add(qn);
}
returnQname[0] = qvec;
if (certs != null) {
returnCert[0] = certs[0];
return certs[0].getSubjectDN();
} else {
WSUsernameTokenPrincipal principal = new WSUsernameTokenPrincipal(
ut.getName(), ut.isHashed());
principal.setNonce(ut.getNonce());
principal.setPassword(ut.getPassword());
principal.setCreatedTime(ut.getCreated());
return principal;
}
} else {
throw new WSSecurityException(WSSecurityException.FAILED_CHECK);
}
} catch (XMLSignatureException e1) {
throw new WSSecurityException(WSSecurityException.FAILED_CHECK);
}
}
/**
* Extracts the certificate(s) from the Binary Security token reference.
* <p/>
*
* @param elem
* The element containing the binary security token. This is
* either X509 certificate(s) or a PKIPath.
* @return an array of X509 certificates
* @throws WSSecurityException
*/
public X509Certificate[] getCertificatesTokenReference(Element elem,
Crypto crypto)
throws WSSecurityException {
BinarySecurity token = createSecurityToken(elem);
if (token instanceof PKIPathSecurity) {
return ((PKIPathSecurity) token).getX509Certificates(false, crypto);
} else if (token instanceof X509Security) {
X509Certificate cert = ((X509Security) token).getX509Certificate(crypto);
X509Certificate[] certs = new X509Certificate[1];
certs[0] = cert;
return certs;
} else {
throw new WSSecurityException(WSSecurityException.UNSUPPORTED_SECURITY_TOKEN,
"unhandledToken", new Object[]{token.getClass().getName()});
}
}
/**
* Extracts the certificate(s) from the SAML token reference.
* <p/>
*
* @param elem The element containing the SAML token.
* @return an array of X509 certificates
* @throws WSSecurityException
*/
protected X509Certificate[] getCertificatesFromSAML(Element elem,
Crypto crypto)
throws WSSecurityException {
/*
* Get some information about the SAML token content. This controls how
* to deal with the whole stuff. First get the Authentication statement
* (includes Subject), then get the _first_ confirmation method only.
*/
SAMLAssertion assertion;
try {
assertion = new SAMLAssertion(elem);
} catch (SAMLException e) {
throw new WSSecurityException(WSSecurityException.FAILURE,
"invalidSAMLToken", new Object[]{"for Signature (cannot parse)"});
}
SAMLSubjectStatement samlSubjS = null;
Iterator it = assertion.getStatements();
while (it.hasNext()) {
SAMLObject so = (SAMLObject) it.next();
if (so instanceof SAMLSubjectStatement) {
samlSubjS = (SAMLSubjectStatement) so;
break;
}
}
SAMLSubject samlSubj = null;
if (samlSubjS != null) {
samlSubj = samlSubjS.getSubject();
}
if (samlSubj == null) {
throw new WSSecurityException(WSSecurityException.FAILURE,
"invalidSAMLToken", new Object[]{"for Signature (no Subject)"});
}
// String confirmMethod = null;
// it = samlSubj.getConfirmationMethods();
// if (it.hasNext()) {
// confirmMethod = (String) it.next();
// }
// boolean senderVouches = false;
// if (SAMLSubject.CONF_SENDER_VOUCHES.equals(confirmMethod)) {
// senderVouches = true;
// }
Element e = samlSubj.getKeyInfo();
X509Certificate[] certs = null;
try {
KeyInfo ki = new KeyInfo(e, null);
if (ki.containsX509Data()) {
X509Data data = ki.itemX509Data(0);
XMLX509Certificate certElem = null;
if (data != null && data.containsCertificate()) {
certElem = data.itemCertificate(0);
}
if (certElem != null) {
X509Certificate cert = certElem.getX509Certificate();
certs = new X509Certificate[1];
certs[0] = cert;
}
}
// TODO: get alias name for cert, check against username set by caller
} catch (XMLSecurityException e3) {
throw new WSSecurityException(WSSecurityException.FAILURE,
"invalidSAMLsecurity",
new Object[]{"cannot get certificate (key holder)"});
}
return certs;
}
/**
* Checks the <code>element</code> and creates appropriate binary security object.
*
* @param element The XML element that contains either a <code>BinarySecurityToken
* </code> or a <code>PKIPath</code> element. Other element types a not
* supported
* @return the BinarySecurity object, either a <code>X509Security</code> or a
* <code>PKIPathSecurity</code> object.
* @throws WSSecurityException
*/
private BinarySecurity createSecurityToken(Element element) throws WSSecurityException {
BinarySecurity token = new BinarySecurity(wssConfig, element);
String type = token.getValueType();
Class clazz = null;
if (wssConfig.getProcessNonCompliantMessages() ||
wssConfig.isBSTValuesPrefixed()) {
if (type.endsWith(X509Security.X509_V3)) {
clazz = X509Security.class;
} else if (type.endsWith(PKIPathSecurity.X509PKI_PATH)) {
clazz = PKIPathSecurity.class;
}
} else {
if (type.equals(X509Security.getType(wssConfig))) {
clazz = X509Security.class;
} else if (type.equals(PKIPathSecurity.getType(wssConfig))) {
clazz = PKIPathSecurity.class;
}
}
if (clazz == null) {
throw new WSSecurityException(WSSecurityException.UNSUPPORTED_SECURITY_TOKEN,
"unsupportedBinaryTokenType", new Object[]{type});
}
try {
Constructor constructor = clazz.getConstructor(constructorType);
if (constructor == null) {
throw new WSSecurityException(WSSecurityException.FAILURE,
"invalidConstructor", new Object[]{clazz});
}
return (BinarySecurity) constructor.newInstance(new Object[]{wssConfig, element});
} catch (InvocationTargetException e) {
Throwable ee = e.getTargetException();
if (ee instanceof WSSecurityException) {
throw (WSSecurityException) ee;
} else {
throw new WSSecurityException(WSSecurityException.FAILURE, null, null, e);
}
} catch (NoSuchMethodException e) {
throw new WSSecurityException(WSSecurityException.FAILURE, null, null, e);
} catch (InstantiationException e) {
throw new WSSecurityException(WSSecurityException.FAILURE, null, null, e);
} catch (IllegalAccessException e) {
throw new WSSecurityException(WSSecurityException.FAILURE, null, null, e);
}
}
/**
* Check the UsernameToken element. Depending on the password type
* contained in the element the processing differs. If the password type
* is password digest (a hashed password) then process the password
* commpletely here. Use the callback class to get a stored password
* perform hash algorithm and compare the result with the transmitted
* password.
* <p/>
* If the password is of type password text or any other yet unknown
* password type the delegate the password validation to the callback
* class. To do so the security engine hands over all necessary data to
* the callback class via the WSPasswordCallback object. To distinguish
* from digested usernam token the usage parameter of WSPasswordCallback
* is set to <code>USERNAME_TOKEN_UNKNOWN</code>
*
* @param token the DOM element that contains the UsernameToken
* @param cb the refernce to the callback object
* @return WSUsernameTokenPrincipal that contain data that an application
* may use to further validate the password/user combination.
* @throws WSSecurityException
*/
public WSUsernameTokenPrincipal handleUsernameToken(Element token, CallbackHandler cb) throws WSSecurityException {
UsernameToken ut = new UsernameToken(wssConfig, token);
String user = ut.getName();
String password = ut.getPassword();
String nonce = ut.getNonce();
String createdTime = ut.getCreated();
String pwType = ut.getPasswordType();
if (doDebug) {
log.debug("UsernameToken user " + user);
log.debug("UsernameToken password " + password);
}
Callback[] callbacks = new Callback[1];
if (ut.isHashed()) {
if (cb == null) {
throw new WSSecurityException(WSSecurityException.FAILURE,
"noCallback");
}
WSPasswordCallback pwCb = new WSPasswordCallback(user, WSPasswordCallback.USERNAME_TOKEN);
callbacks[0] = pwCb;
try {
cb.handle(callbacks);
} catch (IOException e) {
throw new WSSecurityException(WSSecurityException.FAILURE,
"noPassword",
new Object[]{user});
} catch (UnsupportedCallbackException e) {
throw new WSSecurityException(WSSecurityException.FAILURE,
"noPassword",
new Object[]{user});
}
String origPassword = pwCb.getPassword();
if (doDebug) {
log.debug("UsernameToken callback password " + origPassword);
}
if (origPassword == null) {
throw new WSSecurityException(WSSecurityException.FAILURE,
"noPassword", new Object[]{user});
}
if (nonce != null && createdTime != null) {
String passDigest = UsernameToken.doPasswordDigest(nonce, createdTime, origPassword);
if (!passDigest.equals(password)) {
throw new WSSecurityException(WSSecurityException.FAILED_AUTHENTICATION);
}
}
}
else if (cb != null) {
WSPasswordCallback pwCb = new WSPasswordCallback(user, password,
pwType, WSPasswordCallback.USERNAME_TOKEN_UNKNOWN);
callbacks[0] = pwCb;
try {
cb.handle(callbacks);
} catch (IOException e) {
throw new WSSecurityException(WSSecurityException.FAILURE,
"noPassword", new Object[] { user });
} catch (UnsupportedCallbackException e) {
throw new WSSecurityException(WSSecurityException.FAILURE,
"noPassword", new Object[] { user });
}
}
WSUsernameTokenPrincipal principal = new WSUsernameTokenPrincipal(user, ut.isHashed());
principal.setNonce(nonce);
principal.setPassword(password);
principal.setCreatedTime(createdTime);
principal.setPasswordType(pwType);
return principal;
}
public SAMLAssertion handleSAMLToken(Element token) throws WSSecurityException {
boolean result = false;
SAMLAssertion assertion = null;
try {
assertion = new SAMLAssertion(token);
result = true;
if (doDebug) {
log.debug("SAML Assertion issuer " + assertion.getIssuer());
}
} catch (SAMLException e) {
throw new WSSecurityException(WSSecurityException.FAILURE,
"invalidSAMLsecurity", null, e);
}
if (!result) {
throw new WSSecurityException(WSSecurityException.FAILED_AUTHENTICATION);
}
return assertion;
}
public void handleTimestamp(Timestamp timestamp) throws WSSecurityException {
if (doDebug) {
log.debug("Preparing to verify the timestamp");
DateFormat zulu = new XmlSchemaDateFormat();
log.debug("Current time: " + zulu.format(Calendar.getInstance().getTime()));
log.debug("Timestamp created: " + zulu.format(timestamp.getCreated().getTime()));
log.debug("Timestamp expires: " + zulu.format(timestamp.getExpires().getTime()));
}
// Validate whether the security semantics have expired
Calendar rightNow = Calendar.getInstance();
if (timestamp.getExpires().before(rightNow)) {
throw new WSSecurityException(WSSecurityException.INVALID_SECURITY, "invalidTimestamp", new Object[]{"The security semantics of message have expired"});
}
return;
}
public void handleEncryptedKey(Element xencEncryptedKey,
CallbackHandler cb, Crypto crypto) throws WSSecurityException {
handleEncryptedKey(xencEncryptedKey, cb, crypto, null);
}
public void handleEncryptedKey(Element xencEncryptedKey,
PrivateKey privatekey) throws WSSecurityException {
handleEncryptedKey(xencEncryptedKey, null, null, privatekey);
}
public void handleEncryptedKey(Element xencEncryptedKey,
CallbackHandler cb, Crypto crypto, PrivateKey privateKey)
throws WSSecurityException {
long t0 = 0, t1 = 0, t2 = 0;
if (tlog.isDebugEnabled()) {
t0 = System.currentTimeMillis();
}
// need to have it to find the encryped data elements in the envelope
Document doc = xencEncryptedKey.getOwnerDocument();
// lookup xenc:EncryptionMethod, get the Algorithm attribute to determine
// how the key was encrypted. Then check if we support the algorithm
Node tmpE = null; // short living Element used for lookups only
tmpE = (Element) WSSecurityUtil.getDirectChild((Node) xencEncryptedKey,
"EncryptionMethod", WSConstants.ENC_NS);
String keyEncAlgo = null;
if (tmpE != null) {
keyEncAlgo = ((Element) tmpE).getAttribute("Algorithm");
}
if (keyEncAlgo == null) {
throw new WSSecurityException
(WSSecurityException.UNSUPPORTED_ALGORITHM, "noEncAlgo");
}
Cipher cipher = WSSecurityUtil.getCipherInstance(keyEncAlgo);
/*
* Well, we can decrypt the session (symmetric) key. Now lookup CipherValue, this is the value of the
* encrypted session key (session key usually is a symmetrical key that encrypts
* the referenced content). This is a 2-step lookup
*/
Element xencCipherValue = null;
tmpE = (Element) WSSecurityUtil.getDirectChild((Node) xencEncryptedKey, "CipherData", WSConstants.ENC_NS);
if (tmpE != null) {
xencCipherValue = (Element) WSSecurityUtil.getDirectChild((Node) tmpE,
"CipherValue", WSConstants.ENC_NS);
}
if (xencCipherValue == null) {
throw new WSSecurityException
(WSSecurityException.INVALID_SECURITY, "noCipher");
}
// here get the reference to the private key / shared secret key.
// Shared secret key not yet supported
// see check above ... maybe later
if (privateKey == null) {
Element keyInfo = (Element) WSSecurityUtil.getDirectChild((Node) xencEncryptedKey,
"KeyInfo", WSConstants.SIG_NS);
String alias;
if (keyInfo != null) {
Element secRefToken;
if (wssConfig.getProcessNonCompliantMessages()) {
secRefToken = (Element) WSSecurityUtil.getDirectChildWSSE(keyInfo,
"SecurityTokenReference");
} else {
secRefToken = (Element) WSSecurityUtil.getDirectChild(keyInfo,
"SecurityTokenReference", wssConfig.getWsseNS());
}
if (secRefToken == null) {
secRefToken = (Element) WSSecurityUtil.getDirectChild(keyInfo,
"KeyName", WSConstants.SIG_NS);
}
if (secRefToken == null) {
throw new WSSecurityException
(WSSecurityException.INVALID_SECURITY, "noSecTokRef");
}
SecurityTokenReference secRef = new SecurityTokenReference(wssConfig, secRefToken);
/*
* Well, at this point there are several ways to get the key.
* Try to handle all of them :-).
*/
alias = null;
/*
* handle X509IssuerSerial here. First check if all elements are available,
* get the appropriate data, check if all data is available.
* If all is ok up to that point, look up the certificate alias according
* to issuer name and serial number.
* This method is recommended by OASIS WS-S specification, X509 profile
*/
if (secRef.containsX509IssuerSerial()) {
alias = secRef.getX509IssuerSerialAlias(crypto);
if (doDebug) {
log.debug("X509IssuerSerial alias: " + alias);
}
}
/*
* If wsse:KeyIdentifier found, then the public key of the attached cert was used to
* encrypt the session (symmetric) key that encrypts the data. Extract the certificate
* using the BinarySecurity token (was enhanced to handle KeyIdentifier too).
* This method is _not_recommended by OASIS WS-S specification, X509 profile
*/
else if (secRef.containsKeyIdentifier()) {
X509Certificate[] certs = secRef.getKeyIdentifier(crypto);
if (certs == null || certs.length < 1 || certs[0] == null) {
throw new WSSecurityException(WSSecurityException.FAILURE,
"invalidX509Data", new Object[]{"for decryption (KeyId)"});
}
/*
* Here we have the certificate. Now find the alias for it. Needed to identify
* the private key associated with this certificate
*/
alias = crypto.getAliasForX509Cert(certs[0]);
if (doDebug) {
log.debug("cert: " + certs[0]);
log.debug("KeyIdentifier Alias: " + alias);
}
} else if (secRef.containsReference()) {
Element bstElement = secRef.getTokenElement(doc, null);
// at this point ... check token type: Binary
QName el =
new QName(bstElement.getNamespaceURI(),
bstElement.getLocalName());
if (el.equals(binaryToken)) {
X509Security token = null;
String value = bstElement.getAttribute(VALUE_TYPE);
// attempt to get attribute in case it is qualified
if (wssConfig.getProcessNonCompliantMessages()) {
for (int i = 0; i < WSConstants.WSSE_NS_ARRAY.length && value.length() == 0; ++i) {
String ns = WSConstants.WSSE_NS_ARRAY[i];
value = bstElement.getAttributeNS(ns, VALUE_TYPE);
}
}
if (!value.endsWith(X509Security.X509_V3)
|| ((token = new X509Security(wssConfig, bstElement)) == null)) {
throw new WSSecurityException(WSSecurityException.UNSUPPORTED_SECURITY_TOKEN,
"unsupportedBinaryTokenType",
new Object[]{"for decryption (BST)"});
}
X509Certificate cert = token.getX509Certificate(crypto);
if (cert == null) {
throw new WSSecurityException(WSSecurityException.FAILURE,
"invalidX509Data",
new Object[]{"for decryption"});
}
/*
* Here we have the certificate. Now find the alias for it. Needed to identify
* the private key associated with this certificate
*/
alias = crypto.getAliasForX509Cert(cert);
if (doDebug) {
log.debug("BST Alias: " + alias);
}
} else {
throw new WSSecurityException(WSSecurityException.INVALID_SECURITY,
"unsupportedToken",
null);
}
} else if (secRef.containsKeyName()) {
alias = crypto.getAliasForX509Cert(secRef.getKeyNameValue());
if (doDebug) {
log.debug("KeyName alias: " + alias);
}
} else {
throw new WSSecurityException(WSSecurityException.FAILURE, "unsupportedKeyId");
}
} else if (crypto.getDefaultX509Alias() != null) {
alias = crypto.getDefaultX509Alias();
} else {
throw new WSSecurityException
(WSSecurityException.INVALID_SECURITY, "noKeyinfo");
}
/*
* At this point we have all information necessary to decrypt the session
* key:
* - the Cipher object intialized with the correct methods
* - The data that holds the encrypted session key
* - the alias name for the private key
*
* Now use the callback here to get password that enables
* us to read the private key
*/
WSPasswordCallback pwCb = new WSPasswordCallback(alias, WSPasswordCallback.DECRYPT);
Callback[] callbacks = new Callback[1];
callbacks[0] = pwCb;
try {
cb.handle(callbacks);
} catch (IOException e) {
throw new WSSecurityException(WSSecurityException.FAILURE,
"noPassword",
new Object[]{alias});
} catch (UnsupportedCallbackException e) {
throw new WSSecurityException(WSSecurityException.FAILURE,
"noPassword",
new Object[]{alias});
}
String password = pwCb.getPassword();
if (password == null) {
throw new WSSecurityException(WSSecurityException.FAILURE,
"noPassword", new Object[]{alias});
}
try {
privateKey = crypto.getPrivateKey(alias, password);
} catch (Exception e) {
throw new WSSecurityException(WSSecurityException.FAILED_ENC_DEC, null, null, e);
}
}
try {
cipher.init(Cipher.DECRYPT_MODE,
privateKey);
} catch (Exception e1) {
throw new WSSecurityException(WSSecurityException.FAILED_ENC_DEC, null, null, e1);
}
try {
decryptedBytes =
cipher.doFinal(getDecodedBase64EncodedData(xencCipherValue));
} catch (IllegalStateException e2) {
throw new WSSecurityException(WSSecurityException.FAILED_ENC_DEC, null, null, e2);
} catch (IllegalBlockSizeException e2) {
throw new WSSecurityException(WSSecurityException.FAILED_ENC_DEC, null, null, e2);
} catch (BadPaddingException e2) {
throw new WSSecurityException(WSSecurityException.FAILED_ENC_DEC, null, null, e2);
}
if (tlog.isDebugEnabled()) {
t1 = System.currentTimeMillis();
}
/* At this point we have the decrypted session (symmetric) key. According
* to W3C XML-Enc this key is used to decrypt _any_ references contained in
* the reference list
* Now lookup the references that are encrypted with this key
*/
String dataRefURI = null;
Element refList = (Element) WSSecurityUtil.getDirectChild((Node) xencEncryptedKey,
"ReferenceList", WSConstants.ENC_NS);
if (refList != null) {
for (tmpE = refList.getFirstChild();
tmpE != null; tmpE = tmpE.getNextSibling()) {
if (tmpE.getNodeType() != Node.ELEMENT_NODE) {
continue;
}
if (!tmpE.getNamespaceURI().equals(WSConstants.ENC_NS)) {
continue;
}
if (tmpE.getLocalName().equals("DataReference")) {
dataRefURI = ((Element) tmpE).getAttribute("URI");
decryptDataRef(doc, dataRefURI, decryptedBytes);
}
}
}
if (tlog.isDebugEnabled()) {
t2 = System.currentTimeMillis();
tlog.debug("XMLDecrypt: total= " + (t2 - t0) +
", get-sym-key= " + (t1 - t0) +
", decrypt= " + (t2 - t1));
}
return;
}
private void decryptDataRef(Document doc, String dataRefURI, byte[] decryptedData) throws WSSecurityException {
if (doDebug) {
log.debug("found data refernce: " + dataRefURI);
}
/*
* Look up the encrypted data. First try wsu:Id="someURI". If no such Id then
* try the generic lookup to find Id="someURI"
*/
Element encBodyData = null;
if ((encBodyData = WSSecurityUtil.getElementByWsuId(wssConfig, doc, dataRefURI)) == null) {
encBodyData = WSSecurityUtil.getElementByGenId(doc, dataRefURI);
}
if (encBodyData == null) {
throw new WSSecurityException
(WSSecurityException.INVALID_SECURITY,
"dataRef", new Object[]{dataRefURI});
}
boolean content = isContent(encBodyData);
// get the encryprion method
String symEncAlgo = getEncAlgo(encBodyData);
SecretKey symmetricKey = WSSecurityUtil.prepareSecretKey(
symEncAlgo, decryptedData);
// initialize Cipher ....
XMLCipher xmlCipher = null;
try {
xmlCipher = XMLCipher.getInstance(symEncAlgo);
xmlCipher.init(XMLCipher.DECRYPT_MODE, symmetricKey);
} catch (XMLEncryptionException e) {
throw new WSSecurityException(WSSecurityException.UNSUPPORTED_ALGORITHM, null, null, e);
}
if (content) {
encBodyData = (Element) encBodyData.getParentNode();
}
try {
xmlCipher.doFinal(doc, encBodyData, content);
} catch (Exception e1) {
throw new WSSecurityException(WSSecurityException.FAILED_ENC_DEC, null, null, e1);
}
}
/**
* Dereferences and decodes encrypted data elements.
*
* @param elem contains the <code>ReferenceList</code> to the
* encrypted data elements
* @param cb the callback handler to get the key for a key name
* stored if <code>KeyInfo</code> inside the encrypted
* data elements
*/
private void handleReferenceList(Element elem, CallbackHandler cb)
throws WSSecurityException {
Document doc = elem.getOwnerDocument();
Node tmpE = null;
for (tmpE = elem.getFirstChild();
tmpE != null;
tmpE = tmpE.getNextSibling()) {
if (tmpE.getNodeType() != Node.ELEMENT_NODE) {
continue;
}
if (!tmpE.getNamespaceURI().equals(WSConstants.ENC_NS)) {
continue;
}
if (tmpE.getLocalName().equals("DataReference")) {
String dataRefURI = ((Element) tmpE).getAttribute("URI");
decryptDataRefEmbedded(doc, dataRefURI, cb);
}
}
}
public void decryptDataRefEmbedded(Document doc,
String dataRefURI,
CallbackHandler cb)
throws WSSecurityException {
if (doDebug) {
log.debug("Embedded found data refernce: " + dataRefURI);
}
/*
* Look up the encrypted data. First try wsu:Id="someURI". If no such Id then
* try the generic lookup to find Id="someURI"
*/
Element encBodyData = null;
if ((encBodyData = WSSecurityUtil.getElementByWsuId(wssConfig, doc, dataRefURI)) == null) {
encBodyData = WSSecurityUtil.getElementByGenId(doc, dataRefURI);
}
if (encBodyData == null) {
throw new WSSecurityException
(WSSecurityException.INVALID_SECURITY,
"dataRef", new Object[]{dataRefURI});
}
boolean content = isContent(encBodyData);
// Now figure out the encryption algorithm
String symEncAlgo = getEncAlgo(encBodyData);
Element tmpE =
(Element) WSSecurityUtil.findElement((Node) encBodyData,
"KeyInfo",
WSConstants.SIG_NS);
SecretKey symmetricKey = getSharedKey(tmpE, symEncAlgo, cb);
// initialize Cipher ....
XMLCipher xmlCipher = null;
try {
xmlCipher = XMLCipher.getInstance(symEncAlgo);
xmlCipher.init(XMLCipher.DECRYPT_MODE, symmetricKey);
} catch (XMLEncryptionException e1) {
throw new WSSecurityException(WSSecurityException.UNSUPPORTED_ALGORITHM, null, null, e1);
}
if (content) {
encBodyData = (Element) encBodyData.getParentNode();
}
try {
xmlCipher.doFinal(doc, encBodyData, content);
} catch (Exception e) {
throw new WSSecurityException(WSSecurityException.FAILED_ENC_DEC, null, null, e);
}
}
private boolean isContent(Node encBodyData) {
/*
* Depending on the encrypted data type (Content or Element) the encBodyData either
* holds the element whose contents where encrypted, e.g. soapenv:Body, or the
* xenc:EncryptedData element (in case of Element encryption). In either case we need
* to get the xenc:EncryptedData element. So get it. The findElement method returns
* immediatly if its already the correct element.
* Then we can get the Type attribute.
*/
Element tmpE = (Element) WSSecurityUtil.findElement(encBodyData,
"EncryptedData", WSConstants.ENC_NS);
String typeStr = null;
boolean content = true;
if (tmpE != null) {
typeStr = tmpE.getAttribute("Type");
}
if (typeStr != null) {
content = typeStr.equals(WSConstants.ENC_NS + "Content") ? true : false;
}
return content;
}
private String getEncAlgo(Node encBodyData) throws WSSecurityException {
Element tmpE = (Element) WSSecurityUtil.findElement(encBodyData,
"EncryptionMethod", WSConstants.ENC_NS);
String symEncAlgo = null;
if (tmpE != null) {
symEncAlgo = tmpE.getAttribute("Algorithm");
}
if (symEncAlgo == null) {
throw new WSSecurityException
(WSSecurityException.UNSUPPORTED_ALGORITHM,
"noEncAlgo");
}
if (doDebug) {
log.debug("Sym Enc Algo: " + symEncAlgo);
}
return symEncAlgo;
}
protected SecretKey getSharedKey(Element keyInfoElem,
String algorithm,
CallbackHandler cb)
throws WSSecurityException {
String keyName = null;
Element keyNmElem =
(Element) WSSecurityUtil.getDirectChild(keyInfoElem,
"KeyName",
WSConstants.SIG_NS);
if (keyNmElem != null) {
keyNmElem.normalize();
Node tmpN;
if ((tmpN = keyNmElem.getFirstChild()) != null
&& tmpN.getNodeType() == Node.TEXT_NODE) {
keyName = tmpN.getNodeValue();
}
}
if (keyName == null) {
throw new WSSecurityException(WSSecurityException.INVALID_SECURITY,
"noKeyname");
}
WSPasswordCallback pwCb = new WSPasswordCallback(
keyName, WSPasswordCallback.KEY_NAME);
Callback[] callbacks = new Callback[1];
callbacks[0] = pwCb;
try {
cb.handle(callbacks);
} catch (IOException e) {
throw new WSSecurityException(WSSecurityException.FAILURE,
"noPassword",
new Object[]{keyName});
} catch (UnsupportedCallbackException e) {
throw new WSSecurityException(WSSecurityException.FAILURE,
"noPassword",
new Object[]{keyName});
}
byte[] decryptedData = pwCb.getKey();
if (decryptedData == null) {
throw new WSSecurityException(WSSecurityException.FAILURE,
"noPassword",
new Object[]{keyName});
}
return WSSecurityUtil.prepareSecretKey(algorithm, decryptedData);
}
/**
* Method getDecodedBase64EncodedData
* @param element
* @return a byte array containing the decoded data
* @throws WSSecurityException
*/
public static byte[] getDecodedBase64EncodedData(Element element) throws WSSecurityException {
StringBuffer sb = new StringBuffer();
NodeList children = element.getChildNodes();
int iMax = children.getLength();
for (int i = 0; i < iMax; i++) {
Node curr = children.item(i);
if (curr.getNodeType() == Node.TEXT_NODE)
sb.append(((Text) curr).getData());
}
String encodedData = sb.toString();
return Base64.decode(encodedData);
}
/**
* @return the strored decrypted bytes
*/
public byte[] getDecryptedBytes() {
return decryptedBytes;
}
/**
* Should the timestamps have millisecond precision
*/
public void setPrecisionInMilliSeconds(boolean precisionInMilliSeconds) {
wssConfig.setPrecisionInMilliSeconds(precisionInMilliSeconds);
}
}