org.apache.ws.security.message.WSSecDKSign 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
The Apache WSS4J project provides a Java implementation of the primary security standards
for Web Services, namely the OASIS Web Services Security (WS-Security) specifications
from the OASIS Web Services Security TC.
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.message;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.ws.security.SOAPConstants;
import org.apache.ws.security.WSConstants;
import org.apache.ws.security.WSDocInfo;
import org.apache.ws.security.WSDocInfoStore;
import org.apache.ws.security.WSEncryptionPart;
import org.apache.ws.security.WSSecurityException;
import org.apache.ws.security.conversation.ConversationException;
import org.apache.ws.security.message.token.Reference;
import org.apache.ws.security.message.token.SecurityTokenReference;
import org.apache.ws.security.saml.SAMLUtil;
import org.apache.ws.security.transform.STRTransform;
import org.apache.ws.security.util.WSSecurityUtil;
import org.apache.xml.security.algorithms.SignatureAlgorithm;
import org.apache.xml.security.c14n.Canonicalizer;
import org.apache.xml.security.exceptions.XMLSecurityException;
import org.apache.xml.security.keys.KeyInfo;
import org.apache.xml.security.signature.XMLSignature;
import org.apache.xml.security.signature.XMLSignatureException;
import org.apache.xml.security.transforms.TransformationException;
import org.apache.xml.security.transforms.Transforms;
import org.apache.xml.security.transforms.params.InclusiveNamespaces;
import org.apache.xml.security.utils.Constants;
import org.apache.xml.security.utils.XMLUtils;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import java.util.HashSet;
import java.util.Set;
import java.util.Vector;
/**
* Builder to sign with derived keys
*
* @author Ruchith Fernando ([email protected])
* @author Davanum Srinivas ([email protected])
* @author Werner Dittmann ([email protected])
*/
public class WSSecDKSign extends WSSecDerivedKeyBase {
private static Log log = LogFactory.getLog(WSSecDKSign.class.getName());
protected String sigAlgo = XMLSignature.ALGO_ID_MAC_HMAC_SHA1;
protected String canonAlgo = Canonicalizer.ALGO_ID_C14N_EXCL_OMIT_COMMENTS;
protected byte[] signatureValue = null;
private XMLSignature sig = null;
private KeyInfo keyInfo = null;
private String keyInfoUri = null;
private SecurityTokenReference secRef = null;
private String strUri = null;
private WSDocInfo wsDocInfo;
public Document build(Document doc, WSSecHeader secHeader)
throws WSSecurityException, ConversationException {
this.prepare(doc, secHeader);
SOAPConstants soapConstants = WSSecurityUtil.getSOAPConstants(doc.getDocumentElement());
if (parts == null) {
parts = new Vector();
WSEncryptionPart encP =
new WSEncryptionPart(
soapConstants.getBodyQName().getLocalPart(),
soapConstants.getEnvelopeURI(),
"Content"
);
parts.add(encP);
}
addReferencesToSign(parts, secHeader);
this.computeSignature();
this.prependSigToHeader(secHeader);
//
// prepend elements in the right order to the security header
//
this.prependDKElementToHeader(secHeader);
return doc;
}
public void prepare(Document doc, WSSecHeader secHeader)
throws WSSecurityException, ConversationException {
super.prepare(doc);
wsDocInfo = new WSDocInfo(doc);
//
// Get and initialize a XMLSignature element.
//
if (canonAlgo.equals(WSConstants.C14N_EXCL_OMIT_COMMENTS)) {
Element canonElem =
XMLUtils.createElementInSignatureSpace(doc, Constants._TAG_CANONICALIZATIONMETHOD);
canonElem.setAttributeNS(null, Constants._ATT_ALGORITHM, canonAlgo);
if (wssConfig.isWsiBSPCompliant()) {
Set prefixes = getInclusivePrefixes(secHeader.getSecurityHeader(), false);
InclusiveNamespaces inclusiveNamespaces = new InclusiveNamespaces(doc, prefixes);
canonElem.appendChild(inclusiveNamespaces.getElement());
}
try {
SignatureAlgorithm signatureAlgorithm = new SignatureAlgorithm(doc, sigAlgo);
sig = new XMLSignature(doc, null, signatureAlgorithm.getElement(), canonElem);
} catch (XMLSecurityException e) {
log.error("", e);
throw new WSSecurityException(
WSSecurityException.FAILED_SIGNATURE, "noXMLSig", null, e
);
}
} else {
try {
sig = new XMLSignature(doc, null, sigAlgo, canonAlgo);
} catch (XMLSecurityException e) {
log.error("", e);
throw new WSSecurityException(
WSSecurityException.FAILED_SIGNATURE, "noXMLSig", null, e
);
}
}
sig.addResourceResolver(EnvelopeIdResolver.getInstance());
String sigUri = wssConfig.getIdAllocator().createId("Signature-", sig);
sig.setId(sigUri);
keyInfo = sig.getKeyInfo();
keyInfoUri = wssConfig.getIdAllocator().createSecureId("KeyId-", keyInfo);
keyInfo.setId(keyInfoUri);
secRef = new SecurityTokenReference(doc);
strUri = wssConfig.getIdAllocator().createSecureId("STRId-", secRef);
secRef.setID(strUri);
Reference refUt = new Reference(document);
refUt.setURI("#" + this.dktId);
secRef.setReference(refUt);
keyInfo.addUnknownElement(secRef.getElement());
}
protected Set getInclusivePrefixes(Element target) {
return getInclusivePrefixes(target, true);
}
protected Set getInclusivePrefixes(Element target, boolean excludeVisible) {
Set result = new HashSet();
Node parent = target;
NamedNodeMap attributes;
Node attribute;
while (!(parent.getParentNode() instanceof Document)) {
parent = parent.getParentNode();
attributes = parent.getAttributes();
for (int i = 0; i < attributes.getLength(); i++) {
attribute = attributes.item(i);
if (attribute.getNamespaceURI() != null
&& attribute.getNamespaceURI().equals(
org.apache.ws.security.WSConstants.XMLNS_NS
)
) {
if (attribute.getNodeName().equals("xmlns")) {
result.add("#default");
} else {
result.add(attribute.getLocalName());
}
}
}
}
if (excludeVisible == true) {
attributes = target.getAttributes();
for (int i = 0; i < attributes.getLength(); i++) {
attribute = attributes.item(i);
if (attribute.getNamespaceURI() != null
&& attribute.getNamespaceURI().equals(
org.apache.ws.security.WSConstants.XMLNS_NS
)
) {
if (attribute.getNodeName().equals("xmlns")) {
result.remove("#default");
} else {
result.remove(attribute.getLocalName());
}
}
if (attribute.getPrefix() != null) {
result.remove(attribute.getPrefix());
}
}
if (target.getPrefix() == null) {
result.remove("#default");
} else {
result.remove(target.getPrefix());
}
}
return result;
}
/**
* This method adds references to the Signature.
*
* The added references are signed when calling
* computeSignature()
. This method can be called several
* times to add references as required. addReferencesToSign()
* can be called any time after prepare
.
*
* @param references A vector containing WSEncryptionPart
objects
* that define the parts to sign.
* @param secHeader Used to compute namespaces to be inserted by
* InclusiveNamespaces to be WSI compliant.
* @throws WSSecurityException
*/
public void addReferencesToSign(Vector references, WSSecHeader secHeader)
throws WSSecurityException {
Transforms transforms = null;
Element envel = document.getDocumentElement();
for (int part = 0; part < references.size(); part++) {
WSEncryptionPart encPart = (WSEncryptionPart) references.get(part);
String idToSign = encPart.getId();
String elemName = encPart.getName();
String nmSpace = encPart.getNamespace();
//
// Set up the elements to sign. There are two reserved element
// names: "Token" and "STRTransform" "Token": Setup the Signature to
// either sign the information that points to the security token or
// the token itself. If its a direct reference sign the token,
// otherwise sign the KeyInfo Element. "STRTransform": Setup the
// ds:Reference to use STR Transform
//
transforms = new Transforms(document);
try {
if (idToSign != null) {
Element toSignById =
WSSecurityUtil.findElementById(
document.getDocumentElement(), idToSign, WSConstants.WSU_NS);
if (toSignById == null) {
toSignById =
WSSecurityUtil.findElementById(
document.getDocumentElement(), idToSign, null
);
}
transforms.addTransform(Transforms.TRANSFORM_C14N_EXCL_OMIT_COMMENTS);
if (wssConfig.isWsiBSPCompliant()) {
transforms.item(0).getElement().appendChild(
new InclusiveNamespaces(
document, getInclusivePrefixes(toSignById)).getElement()
);
}
sig.addDocument("#" + idToSign, transforms);
} else if (elemName.equals("Token")) {
transforms.addTransform(Transforms.TRANSFORM_C14N_EXCL_OMIT_COMMENTS);
if (wssConfig.isWsiBSPCompliant()) {
transforms.item(0).getElement().appendChild(
new InclusiveNamespaces(document,
getInclusivePrefixes(keyInfo.getElement())).getElement()
);
}
sig.addDocument("#" + keyInfoUri, transforms);
} else if (elemName.equals("STRTransform")) { // STRTransform
Element ctx = createSTRParameter(document);
transforms.addTransform(STRTransform.implementedTransformURI, ctx);
sig.addDocument("#" + strUri, transforms);
} else if (elemName.equals("Assertion")) { // Assertion
String id = SAMLUtil.getAssertionId(envel, elemName, nmSpace);
Element body =
(Element) WSSecurityUtil.findElement(envel, elemName, nmSpace);
if (body == null) {
throw new WSSecurityException(
WSSecurityException.FAILURE,
"noEncElement",
new Object[] {nmSpace + ", " + elemName}
);
}
transforms.addTransform(Transforms.TRANSFORM_C14N_EXCL_OMIT_COMMENTS);
if (wssConfig.isWsiBSPCompliant()) {
transforms.item(0).getElement().appendChild(
new InclusiveNamespaces(
document, getInclusivePrefixes(body)).getElement()
);
}
String prefix =
WSSecurityUtil.setNamespace(body, WSConstants.WSU_NS, WSConstants.WSU_PREFIX);
body.setAttributeNS(WSConstants.WSU_NS, prefix + ":Id", id);
sig.addDocument("#" + id, transforms);
} else {
Element body = (Element) WSSecurityUtil.findElement(envel, elemName, nmSpace);
if (body == null) {
throw new WSSecurityException(
WSSecurityException.FAILURE,
"noEncElement",
new Object[] {nmSpace + ", " + elemName}
);
}
transforms.addTransform(Transforms.TRANSFORM_C14N_EXCL_OMIT_COMMENTS);
if (wssConfig.isWsiBSPCompliant()) {
transforms.item(0).getElement().appendChild(
new InclusiveNamespaces(
document, getInclusivePrefixes(body)).getElement()
);
}
sig.addDocument("#" + setWsuId(body), transforms);
}
} catch (TransformationException e1) {
throw new WSSecurityException(
WSSecurityException.FAILED_SIGNATURE, "noXMLSig", null, e1
);
} catch (XMLSignatureException e1) {
throw new WSSecurityException(
WSSecurityException.FAILED_SIGNATURE, "noXMLSig", null, e1
);
}
}
}
protected Element createSTRParameter(Document doc) {
Element transformParam =
doc.createElementNS(
WSConstants.WSSE_NS,
WSConstants.WSSE_PREFIX + ":TransformationParameters"
);
WSSecurityUtil.setNamespace(
transformParam, WSConstants.WSSE_NS, WSConstants.WSSE_PREFIX
);
Element canonElem =
doc.createElementNS(
WSConstants.SIG_NS, WSConstants.SIG_PREFIX + ":CanonicalizationMethod"
);
WSSecurityUtil.setNamespace(canonElem, WSConstants.SIG_NS, WSConstants.SIG_PREFIX);
canonElem.setAttributeNS(null, "Algorithm", Canonicalizer.ALGO_ID_C14N_EXCL_OMIT_COMMENTS);
transformParam.appendChild(canonElem);
return transformParam;
}
/**
* Prepends the Signature element to the elements already in the Security
* header.
*
* The method can be called any time after prepare()
.
* This allows to insert the Signature element at any position in the
* Security header.
*
* @param secHeader The secHeader that holds the Signature element.
*/
public void prependSigToHeader(WSSecHeader secHeader) {
WSSecurityUtil.prependChildElement(secHeader.getSecurityHeader(), sig.getElement());
}
public void appendSigToHeader(WSSecHeader secHeader) {
Element secHeaderElement = secHeader.getSecurityHeader();
secHeaderElement.appendChild(sig.getElement());
}
/**
* Returns the signature Element.
* The method can be called any time after prepare()
.
* @return the signature element
*/
public Element getSignatureElement() {
return this.sig.getElement();
}
/**
* Compute the Signature over the references.
*
* After references are set this method computes the Signature for them.
* This method can be called any time after the references were set. See
* addReferencesToSign()
.
*
* @throws WSSecurityException
*/
public void computeSignature() throws WSSecurityException {
boolean remove = WSDocInfoStore.store(wsDocInfo);
try {
sig.sign(sig.createSecretKey(derivedKeyBytes));
signatureValue = sig.getSignatureValue();
} catch (XMLSignatureException e1) {
throw new WSSecurityException(
WSSecurityException.FAILED_SIGNATURE, null, null, e1
);
} catch (Exception e1) {
throw new WSSecurityException(
WSSecurityException.FAILED_SIGNATURE, null, null, e1
);
} finally {
if (remove) {
WSDocInfoStore.delete(wsDocInfo);
}
}
}
/**
* @see org.apache.ws.security.message.WSSecDerivedKeyBase#getDerivedKeyLength()
*/
protected int getDerivedKeyLength() throws WSSecurityException {
return (this.derivedKeyLength > 0) ? this.derivedKeyLength :
WSSecurityUtil.getKeyLength(this.sigAlgo);
}
public void setSignatureAlgorithm(String algo) {
this.sigAlgo = algo;
}
/**
* @return Returns the signatureValue.
*/
public byte[] getSignatureValue() {
return signatureValue;
}
/**
* Set the canonicalization method to use.
*
* If the canonicalization method is not set then the recommended Exclusive
* XML Canonicalization is used by default Refer to WSConstants which
* algorithms are supported.
*
* @param algo Is the name of the signature algorithm
* @see WSConstants#C14N_OMIT_COMMENTS
* @see WSConstants#C14N_WITH_COMMENTS
* @see WSConstants#C14N_EXCL_OMIT_COMMENTS
* @see WSConstants#C14N_EXCL_WITH_COMMENTS
*/
public void setSigCanonicalization(String algo) {
canonAlgo = algo;
}
/**
* Get the canonicalization method.
*
* If the canonicalization method was not set then Exclusive XML
* Canonicalization is used by default.
*
* @return The string describing the canonicalization algorithm.
*/
public String getSigCanonicalization() {
return canonAlgo;
}
}