![JAR search and dependency download from the Maven repository](/logo.png)
org.apache.ws.security.util.WSSecurityUtil Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of wss4j Show documentation
Show all versions of wss4j Show documentation
Apache WSS4J is an implementation of the Web Services Security
(WS-Security) being developed at OASIS Web Services Security TC.
WSS4J is a primarily a Java library that can be used to sign and
verify SOAP Messages with WS-Security information. WSS4J will
use Apache Axis and Apache XML-Security projects and will be
interoperable with JAX-RPC based server/clients and .NET
server/clients.
/*
* Copyright 2003-2006 The Apache Software Foundation, or their licensors, as
* appropriate.
*
* 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.util;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.ws.security.SOAP11Constants;
import org.apache.ws.security.SOAP12Constants;
import org.apache.ws.security.SOAPConstants;
import org.apache.ws.security.WSConstants;
import org.apache.ws.security.WSSecurityEngineResult;
import org.apache.ws.security.WSSecurityException;
import org.apache.ws.security.handler.WSHandlerConstants;
import org.apache.ws.security.handler.WSHandlerResult;
import org.apache.ws.security.message.token.BinarySecurity;
import org.apache.ws.security.message.token.X509Security;
import org.apache.xml.security.algorithms.JCEMapper;
import org.apache.xml.security.signature.XMLSignature;
import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.Text;
import javax.crypto.Cipher;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import javax.xml.namespace.QName;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.cert.X509Certificate;
import java.util.Iterator;
import java.util.Set;
import java.util.Vector;
/**
* WS-Security Utility methods.
*
* @author Davanum Srinivas ([email protected]).
*/
public class WSSecurityUtil {
private static Log log = LogFactory.getLog(WSSecurityUtil.class);
private static boolean doDebug = false;
static {
doDebug = log.isDebugEnabled();
}
/**
* A cached pseuo-random number generator
* NB. On some JVMs, caching this random number
* generator is required to overcome punitive
* overhead.
*/
private static SecureRandom random = null;
/**
* Returns the first WS-Security header element for a given actor. Only one
* WS-Security header is allowed for an actor.
*
* @param doc
* @param actor
* @return the wsse:Security
element or null
* if not such element found
*/
public static Element getSecurityHeader(Document doc, String actor,
SOAPConstants sc) {
Element soapHeaderElement = (Element) getDirectChild(doc
.getDocumentElement(), sc.getHeaderQName().getLocalPart(), sc
.getEnvelopeURI());
if (soapHeaderElement == null) { // no SOAP header at all
return null;
}
// get all wsse:Security nodes
NodeList list = null;
int len = 0;
list = soapHeaderElement.getElementsByTagNameNS(WSConstants.WSSE_NS,
WSConstants.WSSE_LN);
if (list == null) {
return null;
} else {
len = list.getLength();
}
Element elem;
Attr attr;
String hActor;
for (int i = 0; i < len; i++) {
elem = (Element) list.item(i);
attr = elem.getAttributeNodeNS(sc.getEnvelopeURI(), sc
.getRoleAttributeQName().getLocalPart());
hActor = (attr != null) ? attr.getValue() : null;
if (WSSecurityUtil.isActorEqual(actor, hActor)) {
return elem;
}
}
return null;
}
/**
* Compares two actor strings and returns true if these are equal. Takes
* care of the null length strings and uses ignore case.
*
* @param actor
* @param hActor
* @return TODO
*/
public static boolean isActorEqual(String actor, String hActor) {
if ((((hActor == null) || (hActor.length() == 0)) && ((actor == null) || (actor
.length() == 0)))
|| ((hActor != null) && (actor != null) && hActor
.equalsIgnoreCase(actor))) {
return true;
} else {
return false;
}
}
/**
* Gets a direct child with specified localname and namespace.
*
* @param fNode
* the node where to start the search
* @param localName
* local name of the child to get
* @param namespace
* the namespace of the child to get
* @return the node or null
if not such node found
*/
public static Node getDirectChild(Node fNode, String localName,
String namespace) {
for (Node currentChild = fNode.getFirstChild(); currentChild != null; currentChild = currentChild
.getNextSibling()) {
if (localName.equals(currentChild.getLocalName())
&& namespace.equals(currentChild.getNamespaceURI())) {
return currentChild;
}
}
return null;
}
/**
* return the first soap "Body" element.
*
* @param doc
* @return the body element or null
if document does not
* contain a SOAP body
*/
public static Element findBodyElement(Document doc, SOAPConstants sc) {
Element soapBodyElement = (Element) WSSecurityUtil.getDirectChild(doc
.getFirstChild(), sc.getBodyQName().getLocalPart(), sc
.getEnvelopeURI());
return soapBodyElement;
}
/**
* Returns the first element that matches name
and
* namespace
. This is a replacement for a XPath lookup
* //name
with the given namespace. It's somewhat faster than
* XPath, and we do not deal with prefixes, just with the real namespace URI
*
* @param startNode
* Where to start the search
* @param name
* Local name of the element
* @param namespace
* Namespace URI of the element
* @return The found element or null
*/
public static Node findElement(Node startNode, String name, String namespace) {
/*
* Replace the formely recursive implementation with a depth-first-loop
* lookup
*/
if (startNode == null) {
return null;
}
Node startParent = startNode.getParentNode();
Node processedNode = null;
while (startNode != null) {
// start node processing at this point
if (startNode.getNodeType() == Node.ELEMENT_NODE
&& startNode.getLocalName().equals(name)) {
String ns = startNode.getNamespaceURI();
if (ns != null && ns.equals(namespace)) {
return startNode;
}
if ((namespace == null || namespace.length() == 0)
&& (ns == null || ns.length() == 0)) {
return startNode;
}
}
processedNode = startNode;
startNode = startNode.getFirstChild();
// no child, this node is done.
if (startNode == null) {
// close node processing, get sibling
startNode = processedNode.getNextSibling();
}
// no more siblings, get parent, all children
// of parent are processed.
while (startNode == null) {
processedNode = processedNode.getParentNode();
if (processedNode == startParent) {
return null;
}
// close parent node processing (processed node now)
startNode = processedNode.getNextSibling();
}
}
return null;
}
/**
* Returns the single element that containes an Id with value
* uri
and namespace
. This is a
* replacement for a XPath Id lookup with the given namespace. It's somewhat
* faster than XPath, and we do not deal with prefixes, just with the real
* namespace URI
*
* If there are multiple elements, we log a warning and return null as this
* can be used to get around the signature checking.
*
* @param startNode
* Where to start the search
* @param value
* Value of the Id attribute
* @param namespace
* Namespace URI of the Id
* @return The found element if there was exactly one match, or
* null
otherwise
*/
public static Element findElementById(Node startNode, String value,
String namespace) {
Element foundElement = null;
/*
* Replace the formely recursive implementation with a depth-first-loop
* lookup
*/
if (startNode == null) {
return null;
}
Node startParent = startNode.getParentNode();
Node processedNode = null;
while (startNode != null) {
// start node processing at this point
if (startNode.getNodeType() == Node.ELEMENT_NODE) {
Element se = (Element) startNode;
if (se.hasAttributeNS(namespace, "Id")
&& value.equals(se.getAttributeNS(namespace, "Id"))) {
if (foundElement == null) {
foundElement = se; // Continue searching to find
// duplicates
} else {
log
.warn("Multiple elements with the same 'Id' attribute value!");
return null;
}
}
}
processedNode = startNode;
startNode = startNode.getFirstChild();
// no child, this node is done.
if (startNode == null) {
// close node processing, get sibling
startNode = processedNode.getNextSibling();
}
// no more siblings, get parent, all children
// of parent are processed.
while (startNode == null) {
processedNode = processedNode.getParentNode();
if (processedNode == startParent) {
return foundElement;
}
// close parent node processing (processed node now)
startNode = processedNode.getNextSibling();
}
}
return foundElement;
}
/**
* set the namespace if it is not set already.
*
* @param element
* @param namespace
* @param prefix
* @return TODO
*/
public static String setNamespace(Element element, String namespace,
String prefix) {
String pre = getPrefixNS(namespace, element);
if (pre != null) {
return pre;
}
element.setAttributeNS(WSConstants.XMLNS_NS, "xmlns:" + prefix,
namespace);
return prefix;
}
/*
* ** The following methods were copied over from aixs.utils.XMLUtils and
* adapted
*/
public static String getPrefixNS(String uri, Node e) {
while (e != null && (e.getNodeType() == Element.ELEMENT_NODE)) {
NamedNodeMap attrs = e.getAttributes();
for (int n = 0; n < attrs.getLength(); n++) {
Attr a = (Attr) attrs.item(n);
String name;
if ((name = a.getName()).startsWith("xmlns:")
&& a.getNodeValue().equals(uri)) {
return name.substring(6);
}
}
e = e.getParentNode();
}
return null;
}
public static String getNamespace(String prefix, Node e) {
while (e != null && (e.getNodeType() == Node.ELEMENT_NODE)) {
Attr attr = null;
if (prefix == null) {
attr = ((Element) e).getAttributeNode("xmlns");
} else {
attr = ((Element) e).getAttributeNodeNS(WSConstants.XMLNS_NS,
prefix);
}
if (attr != null)
return attr.getValue();
e = e.getParentNode();
}
return null;
}
/**
* Return a QName when passed a string like "foo:bar" by mapping the "foo"
* prefix to a namespace in the context of the given Node.
*
* @return a QName generated from the given string representation
*/
public static QName getQNameFromString(String str, Node e) {
return getQNameFromString(str, e, false);
}
/**
* Return a QName when passed a string like "foo:bar" by mapping the "foo"
* prefix to a namespace in the context of the given Node. If default
* namespace is found it is returned as part of the QName.
*
* @return a QName generated from the given string representation
*/
public static QName getFullQNameFromString(String str, Node e) {
return getQNameFromString(str, e, true);
}
private static QName getQNameFromString(String str, Node e,
boolean defaultNS) {
if (str == null || e == null)
return null;
int idx = str.indexOf(':');
if (idx > -1) {
String prefix = str.substring(0, idx);
String ns = getNamespace(prefix, e);
if (ns == null)
return null;
return new QName(ns, str.substring(idx + 1));
} else {
if (defaultNS) {
String ns = getNamespace(null, e);
if (ns != null)
return new QName(ns, str);
}
return new QName("", str);
}
}
/**
* Return a string for a particular QName, mapping a new prefix if
* necessary.
*/
public static String getStringForQName(QName qname, Element e) {
String uri = qname.getNamespaceURI();
String prefix = getPrefixNS(uri, e);
if (prefix == null) {
int i = 1;
prefix = "ns" + i;
while (getNamespace(prefix, e) != null) {
i++;
prefix = "ns" + i;
}
e.setAttributeNS(WSConstants.XMLNS_NS, "xmlns:" + prefix, uri);
}
return prefix + ":" + qname.getLocalPart();
}
/* ** up to here */
/**
* Search for an element given its wsu:id.
*
* @param doc
* the DOM document (SOAP request)
* @param id
* the Id of the element
* @return the found element or null if no element with the Id exists
*/
public static Element getElementByWsuId(Document doc, String id) {
if (id == null) {
return null;
}
id = getIDfromReference(id);
return WSSecurityUtil.findElementById(doc.getDocumentElement(), id,
WSConstants.WSU_NS);
}
/**
* Turn a reference (eg "#5") into an ID (eg "5").
*
* @param ref
* @return ref trimmed and with the leading "#" removed, or null if not
* correctly formed
*/
public static String getIDfromReference(String ref) {
String id = ref.trim();
if ((id.length() == 0) || (id.charAt(0) != '#')) {
return null;
}
return id.substring(1);
}
/**
* Search for an element given its generic id.
*
* @param doc
* the DOM document (SOAP request)
* @param id
* the Id of the element
* @return the found element or null if no element with the Id exists
*/
public static Element getElementByGenId(Document doc, String id) {
if (id == null) {
return null;
}
id = id.trim();
if ((id.length() == 0) || (id.charAt(0) != '#')) {
return null;
}
id = id.substring(1);
return WSSecurityUtil.findElementById(doc.getDocumentElement(), id,
null);
}
/**
* create a new element in the same namespace
*
* @param parent
* for the new element
* @param localName
* of the new element
* @return the new element
*/
private static Element createElementInSameNamespace(Element parent,
String localName) {
String qName = localName;
String prefix = parent.getPrefix();
if (prefix != null && prefix.length() > 0) {
qName = prefix + ":" + localName;
}
String nsUri = parent.getNamespaceURI();
return parent.getOwnerDocument().createElementNS(nsUri, qName);
}
/**
* find a child element with given namespace and local name
*
* @param parent
* the node to start the search
* @param namespaceUri
* of the element
* @param localName
* of the eleme
* @return the found element or null if the element does not exist
*/
private static Element findChildElement(Element parent,
String namespaceUri, String localName) {
NodeList children = parent.getChildNodes();
int len = children.getLength();
for (int i = 0; i < len; i++) {
Node child = children.item(i);
if (child.getNodeType() == Node.ELEMENT_NODE) {
Element elementChild = (Element) child;
if (namespaceUri.equals(elementChild.getNamespaceURI())
&& localName.equals(elementChild.getLocalName())) {
return elementChild;
}
}
}
return null;
}
/**
* append a child element
*
* @param doc
* the DOM document (SOAP request)
* @param parent
* element of this child element
* @param child
* the element to append
* @return the child element
*/
public static Element appendChildElement(Document doc, Element parent,
Element child) {
Node whitespaceText = doc.createTextNode("\n");
parent.appendChild(whitespaceText);
parent.appendChild(child);
return child;
}
/**
* prepend a child element
*
* @param doc
* the DOM document (SOAP request)
* @param parent
* element of this child element
* @param child
* the element to append
* @param addWhitespace
* if true prepend a newline before child
* @return the child element
*/
public static Element prependChildElement(Document doc, Element parent,
Element child, boolean addWhitespace) {
Node firstChild = parent.getFirstChild();
if (firstChild == null) {
parent.appendChild(child);
} else {
parent.insertBefore(child, firstChild);
}
if (addWhitespace) {
Node whitespaceText = doc.createTextNode("\n");
parent.insertBefore(whitespaceText, child);
}
return child;
}
/**
* find the first ws-security header block
*
* @param doc
* the DOM document (SOAP request)
* @param envelope
* the SOAP envelope
* @param doCreate
* if true create a new WSS header block if none exists
* @return the WSS header or null if none found and doCreate is false
*/
public static Element findWsseSecurityHeaderBlock(Document doc,
Element envelope, boolean doCreate) {
return findWsseSecurityHeaderBlock(doc, envelope, null, doCreate);
}
/**
* find a ws-security header block for a given actor
*
* @param doc
* the DOM document (SOAP request)
* @param envelope
* the SOAP envelope
* @param actor
* the acttoer (role) name of the WSS header
* @param doCreate
* if true create a new WSS header block if none exists
* @return the WSS header or null if none found and doCreate is false
*/
public static Element findWsseSecurityHeaderBlock(Document doc,
Element envelope, String actor, boolean doCreate) {
SOAPConstants sc = getSOAPConstants(envelope);
Element wsseSecurity = getSecurityHeader(doc, actor, sc);
if (wsseSecurity != null) {
return wsseSecurity;
}
Element header = findChildElement(envelope, sc.getEnvelopeURI(), sc
.getHeaderQName().getLocalPart());
if (header == null) {
if (doCreate) {
header = createElementInSameNamespace(envelope, sc
.getHeaderQName().getLocalPart());
header = prependChildElement(doc, envelope, header, true);
}
}
if (doCreate) {
wsseSecurity = header.getOwnerDocument().createElementNS(
WSConstants.WSSE_NS, "wsse:Security");
wsseSecurity.setAttributeNS(WSConstants.XMLNS_NS, "xmlns:wsse",
WSConstants.WSSE_NS);
return prependChildElement(doc, header, wsseSecurity, true);
}
return null;
}
/**
* create a base64 test node
*
* @param doc
* the DOM document (SOAP request)
* @param data
* to encode
* @return a Text node containing the base64 encoded data
*/
public static Text createBase64EncodedTextNode(Document doc, byte data[]) {
return doc.createTextNode(Base64.encode(data));
}
public static SecretKey prepareSecretKey(String symEncAlgo, byte[] rawKey) {
SecretKeySpec keySpec = new SecretKeySpec(rawKey, JCEMapper
.getJCEKeyAlgorithmFromURI(symEncAlgo));
return (SecretKey) keySpec;
}
public static SOAPConstants getSOAPConstants(Element startElement) {
Document doc = startElement.getOwnerDocument();
String ns = doc.getDocumentElement().getNamespaceURI();
if (WSConstants.URI_SOAP12_ENV.equals(ns)) {
return new SOAP12Constants();
} else {
return new SOAP11Constants();
}
}
public static Cipher getCipherInstance(String cipherAlgo)
throws WSSecurityException {
Cipher cipher = null;
try {
if (cipherAlgo.equalsIgnoreCase(WSConstants.KEYTRANSPORT_RSA15)) {
cipher = Cipher.getInstance("RSA/NONE/PKCS1PADDING");
} else if (cipherAlgo
.equalsIgnoreCase(WSConstants.KEYTRANSPORT_RSAOEP)) {
cipher = Cipher.getInstance("RSA/NONE/OAEPPADDING");
} else {
throw new WSSecurityException(
WSSecurityException.UNSUPPORTED_ALGORITHM,
"unsupportedKeyTransp", new Object[] { cipherAlgo });
}
} catch (NoSuchPaddingException ex) {
throw new WSSecurityException(
WSSecurityException.UNSUPPORTED_ALGORITHM,
"unsupportedKeyTransp", new Object[] { "No such padding: "
+ cipherAlgo });
} catch (NoSuchAlgorithmException ex) {
throw new WSSecurityException(
WSSecurityException.UNSUPPORTED_ALGORITHM,
"unsupportedKeyTransp",
new Object[] { "No such algorithm: " + cipherAlgo });
}
return cipher;
}
/**
* Fetch the result of a given action from a given result vector
*
* @param wsResultVector
* The result vector to fetch an action from
* @param action
* The action to fetch
* @return The result fetched from the result vector, null if the result
* could not be found
*/
public static WSSecurityEngineResult fetchActionResult(
Vector wsResultVector, int action) {
WSSecurityEngineResult wsResult = null;
// Find the part of the security result that matches the given action
for (int i = 0; i < wsResultVector.size(); i++) {
// Check the result of every action whether it matches the given
// action
if (((WSSecurityEngineResult) wsResultVector.get(i)).getAction() == action) {
wsResult = (WSSecurityEngineResult) wsResultVector.get(i);
}
}
return wsResult;
}
/**
* Fetch the result of a given action from a given result vector
*
* @param wsResultVector
* The result vector to fetch an action from
* @param action
* The action to fetch
* @param results
* where to store the found results data for the action
* @return The result fetched from the result vector, null if the result
* could not be found
*/
public static Vector fetchAllActionResults(Vector wsResultVector,
int action, Vector results) {
// Find the parts of the security result that matches the given action
for (int i = 0; i < wsResultVector.size(); i++) {
// Check the result of every action whether it matches the given
// action
if (((WSSecurityEngineResult) wsResultVector.get(i)).getAction() == action) {
results.add(wsResultVector.get(i));
}
}
return results;
}
static public int decodeAction(String action, Vector actions)
throws WSSecurityException {
int doAction = 0;
if (action == null) {
return doAction;
}
String single[] = StringUtil.split(action, ' ');
for (int i = 0; i < single.length; i++) {
if (single[i].equals(WSHandlerConstants.NO_SECURITY)) {
doAction = WSConstants.NO_SECURITY;
return doAction;
} else if (single[i].equals(WSHandlerConstants.USERNAME_TOKEN)) {
doAction |= WSConstants.UT;
actions.add(new Integer(WSConstants.UT));
} else if (single[i].equals(WSHandlerConstants.SIGNATURE)) {
doAction |= WSConstants.SIGN;
actions.add(new Integer(WSConstants.SIGN));
} else if (single[i].equals(WSHandlerConstants.ENCRYPT)) {
doAction |= WSConstants.ENCR;
actions.add(new Integer(WSConstants.ENCR));
} else if (single[i].equals(WSHandlerConstants.SAML_TOKEN_UNSIGNED)) {
doAction |= WSConstants.ST_UNSIGNED;
actions.add(new Integer(WSConstants.ST_UNSIGNED));
} else if (single[i].equals(WSHandlerConstants.SAML_TOKEN_SIGNED)) {
doAction |= WSConstants.ST_SIGNED;
actions.add(new Integer(WSConstants.ST_SIGNED));
} else if (single[i].equals(WSHandlerConstants.TIMESTAMP)) {
doAction |= WSConstants.TS;
actions.add(new Integer(WSConstants.TS));
} else if (single[i].equals(WSHandlerConstants.NO_SERIALIZATION)) {
doAction |= WSConstants.NO_SERIALIZE;
actions.add(new Integer(WSConstants.NO_SERIALIZE));
} else if (single[i].equals(WSHandlerConstants.SIGN_WITH_UT_KEY)) {
doAction |= WSConstants.UT_SIGN;
actions.add(new Integer(WSConstants.UT_SIGN));
} else {
throw new WSSecurityException(
"WSDoAllSender: Unknown action defined" + single[i]);
}
}
return doAction;
}
/**
* Returns the length of the key in # of bytes
*
* @param algorithm
* @return
*/
public static int getKeyLength(String algorithm) throws WSSecurityException {
if (algorithm.equals(WSConstants.TRIPLE_DES)) {
return 24;
} else if (algorithm.equals(WSConstants.AES_128)) {
return 16;
} else if (algorithm.equals(WSConstants.AES_192)) {
return 24;
} else if (algorithm.equals(WSConstants.AES_256)) {
return 32;
} else if (XMLSignature.ALGO_ID_MAC_HMAC_SHA1.equals(algorithm)) {
return 20;
} else if (XMLSignature.ALGO_ID_MAC_HMAC_SHA256.equals(algorithm)) {
return 32;
} else if (XMLSignature.ALGO_ID_MAC_HMAC_SHA384.equals(algorithm)) {
return 48;
} else if (XMLSignature.ALGO_ID_MAC_HMAC_SHA512.equals(algorithm)) {
return 64;
} else if (XMLSignature.ALGO_ID_MAC_HMAC_NOT_RECOMMENDED_MD5
.equals(algorithm)) {
return 16;
} else {
throw new WSSecurityException(
WSSecurityException.UNSUPPORTED_ALGORITHM, null, null, null);
}
}
/**
* Generate a nonce of the given length
*
* @return
* @throws Exception
*/
public static byte[] generateNonce(int length) throws WSSecurityException {
try {
final SecureRandom r = resolveSecureRandom();
if (r == null) {
throw new WSSecurityException("Random generator is not initialzed.");
}
byte[] temp = new byte[length];
r.nextBytes(temp);
return temp;
} catch (Exception e) {
throw new WSSecurityException(
"Error in generating nonce of length " + length, e);
}
}
/**
* Search through a WSS4J results vector for a single signature covering all
* these elements.
*
* NOTE: it is important that the given elements are those that are
* referenced using wsu:Id. When the signed element is referenced using a
* transformation such as XPath filtering the validation is carried out
* in signature verification itself.
*
* @param results
* results (e.g., as stored as WSHandlerConstants.RECV_RESULTS on
* an Axis MessageContext)
* @param elements
* the elements to check
* @return the identity of the signer
* @throws WSSecurityException
* if no suitable signature could be found or if any element
* didn't have a wsu:Id attribute
*/
public static X509Certificate ensureSignedTogether(Iterator results,
Element[] elements) throws WSSecurityException {
log.debug("ensureSignedTogether()");
if (results == null)
throw new IllegalArgumentException("No results vector");
if (elements == null || elements.length == 0)
throw new IllegalArgumentException("No elements to check!");
// Turn the list of required elements into a list of required wsu:Id
// strings
String[] requiredIDs = new String[elements.length];
for (int i = 0; i < elements.length; i++) {
Element e = (Element) elements[i];
if (e == null) {
throw new IllegalArgumentException("elements[" + i
+ "] is null!");
}
requiredIDs[i] = e.getAttributeNS(WSConstants.WSU_NS, "Id");
if (requiredIDs[i] == null) {
throw new WSSecurityException(WSSecurityException.FAILED_CHECK,
"requiredElementNoID", new Object[] { e.getNodeName() });
}
log.debug("Required element " + e.getNodeName() + " has wsu:Id "
+ requiredIDs[i]);
}
WSSecurityException fault = null;
// Search through the results for a SIGN result
while (results.hasNext()) {
WSHandlerResult result = (WSHandlerResult) results.next();
Iterator actions = result.getResults().iterator();
while (actions.hasNext()) {
WSSecurityEngineResult resultItem = (WSSecurityEngineResult) actions
.next();
if (resultItem.getAction() == WSConstants.SIGN) {
try {
checkSignsAllElements(resultItem, requiredIDs);
return resultItem.getCertificate();
} catch (WSSecurityException ex) {
// Store the exception but keep going... there may be a
// better signature later
log
.debug(
"SIGN result does not sign all required elements",
ex);
fault = ex;
}
}
}
}
if (fault != null)
throw fault;
throw new WSSecurityException(WSSecurityException.FAILED_CHECK,
"noSignResult");
}
/**
* Ensure that this signature covers all required elements (identified by
* their wsu:Id attributes).
*
* @param resultItem
* the signature to check
* @param requiredIDs
* the list of wsu:Id values that must be covered
* @throws WSSecurityException
* if any required element is not included
*/
private static void checkSignsAllElements(
WSSecurityEngineResult resultItem, String[] requiredIDs)
throws WSSecurityException {
if (resultItem.getAction() != WSConstants.SIGN)
throw new IllegalArgumentException("Not a SIGN result");
Set sigElems = resultItem.getSignedElements();
if (sigElems == null)
throw new RuntimeException(
"Missing signedElements set in WSSecurityEngineResult!");
log.debug("Found SIGN result...");
for (Iterator i = sigElems.iterator(); i.hasNext();) {
Object sigElement = i.next();
if(sigElement instanceof String) {
log.debug("Signature includes element with ID " + sigElement);
} else {
log.debug("Signature includes element with null uri " +
sigElement.toString());
}
}
log.debug("Checking required elements are in the signature...");
for (int i = 0; i < requiredIDs.length; i++) {
if (!sigElems.contains(requiredIDs[i])) {
throw new WSSecurityException(WSSecurityException.FAILED_CHECK,
"requiredElementNotSigned",
new Object[] { requiredIDs[i] });
}
log.debug("Element with ID " + requiredIDs[i]
+ " was correctly signed");
}
log.debug("All required elements are signed");
}
/**
* @return a SecureRandom instance initialized with the "SHA1PRNG"
* algorithm identifier
*/
public static SecureRandom
resolveSecureRandom() throws NoSuchAlgorithmException {
return resolveSecureRandom("SHA1PRNG");
}
/**
* @param algorithm
*
*
* @return a SecureRandom instance initialize with the identifier
* specified in algorithm
*/
public synchronized static SecureRandom
resolveSecureRandom(
final String algorithm
) throws NoSuchAlgorithmException {
if (random == null) {
random = SecureRandom.getInstance(algorithm);
random.setSeed(System.currentTimeMillis());
}
return random;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy