Author: giger
Date: Mon Jun 10 18:25:45 2013
New Revision: 1491556
URL: http://svn.apache.org/r1491556
Log:
WSS-450 - Inbound Processing code fails with an Encrypted Signature
Modified:
webservices/wss4j/trunk/ws-security-stax/src/main/java/org/apache/wss4j/stax/impl/processor/output/SecurityHeaderReorderProcessor.java
webservices/wss4j/trunk/ws-security-stax/src/test/java/org/apache/wss4j/stax/test/HeaderOrderingTest.java
Modified: webservices/wss4j/trunk/ws-security-stax/src/main/java/org/apache/wss4j/stax/impl/processor/output/SecurityHeaderReorderProcessor.java
URL: http://svn.apache.org/viewvc/webservices/wss4j/trunk/ws-security-stax/src/main/java/org/apache/wss4j/stax/impl/processor/output/SecurityHeaderReorderProcessor.java?rev=1491556&r1=1491555&r2=1491556&view=diff
==============================================================================
--- webservices/wss4j/trunk/ws-security-stax/src/main/java/org/apache/wss4j/stax/impl/processor/output/SecurityHeaderReorderProcessor.java
(original)
+++ webservices/wss4j/trunk/ws-security-stax/src/main/java/org/apache/wss4j/stax/impl/processor/output/SecurityHeaderReorderProcessor.java
Mon Jun 10 18:25:45 2013
@@ -31,7 +31,6 @@ import org.apache.xml.security.stax.ext.
import org.apache.xml.security.stax.ext.stax.XMLSecStartElement;
import org.apache.xml.security.stax.impl.processor.output.FinalOutputProcessor;
-import javax.xml.namespace.QName;
import javax.xml.stream.XMLStreamConstants;
import javax.xml.stream.XMLStreamException;
import java.util.*;
@@ -46,8 +45,8 @@ import java.util.*;
*/
public class SecurityHeaderReorderProcessor extends AbstractOutputProcessor {
- final private Map<XMLSecurityConstants.Action, Map<QName, Deque<XMLSecEvent>>>
actionEventMap =
- new LinkedHashMap<XMLSecurityConstants.Action, Map<QName, Deque<XMLSecEvent>>>();
+ final private Map<XMLSecurityConstants.Action, Map<SecurityHeaderOrder, Deque<XMLSecEvent>>>
actionEventMap =
+ new LinkedHashMap<XMLSecurityConstants.Action, Map<SecurityHeaderOrder,
Deque<XMLSecEvent>>>();
private int securityHeaderIndex = 0;
private Deque<XMLSecEvent> currentDeque;
@@ -65,12 +64,12 @@ public class SecurityHeaderReorderProces
XMLSecurityConstants.Action[] outActions = getSecurityProperties().getOutAction();
for (int i = outActions.length - 1; i >= 0; i--) {
XMLSecurityConstants.Action outAction = outActions[i];
- actionEventMap.put(outAction, new TreeMap<QName, Deque<XMLSecEvent>>(new
Comparator<QName>() {
+ actionEventMap.put(outAction, new TreeMap<SecurityHeaderOrder, Deque<XMLSecEvent>>(new
Comparator<SecurityHeaderOrder>() {
@Override
- public int compare(QName o1, QName o2) {
- if (WSSConstants.TAG_dsig_Signature.equals(o1)) {
+ public int compare(SecurityHeaderOrder o1, SecurityHeaderOrder o2) {
+ if (WSSConstants.TAG_dsig_Signature.equals(o1.getSecurityHeaderElementName()))
{
return 1;
- } else if (WSSConstants.TAG_dsig_Signature.equals(o2)) {
+ } else if (WSSConstants.TAG_dsig_Signature.equals(o2.getSecurityHeaderElementName()))
{
return -1;
}
return 1;
@@ -95,12 +94,43 @@ public class SecurityHeaderReorderProces
if (xmlSecEvent.isEndElement() && xmlSecEvent.asEndElement().getName().equals(WSSConstants.TAG_wsse_Security))
{
OutputProcessorChain subOutputProcessorChain = outputProcessorChain.createSubChain(this);
- Iterator<Map.Entry<XMLSecurityConstants.Action, Map<QName, Deque<XMLSecEvent>>>>
iterator = actionEventMap.entrySet().iterator();
+ Iterator<Map.Entry<XMLSecurityConstants.Action, Map<SecurityHeaderOrder,
Deque<XMLSecEvent>>>> iterator = actionEventMap.entrySet().iterator();
+ loop:
while (iterator.hasNext()) {
- Map.Entry<XMLSecurityConstants.Action, Map<QName, Deque<XMLSecEvent>>>
next = iterator.next();
- Iterator<Map.Entry<QName, Deque<XMLSecEvent>>> entryIterator
= next.getValue().entrySet().iterator();
+ Map.Entry<XMLSecurityConstants.Action, Map<SecurityHeaderOrder,
Deque<XMLSecEvent>>> next = iterator.next();
+
+ boolean encryptAction = false;
+ Iterator<Map.Entry<SecurityHeaderOrder, Deque<XMLSecEvent>>>
entryIterator = next.getValue().entrySet().iterator();
while (entryIterator.hasNext()) {
- Map.Entry<QName, Deque<XMLSecEvent>> entry = entryIterator.next();
+ Map.Entry<SecurityHeaderOrder, Deque<XMLSecEvent>> entry
= entryIterator.next();
+ //output all non encrypted headers until...
+ if (!entry.getKey().isEncrypted()) {
+ Deque<XMLSecEvent> xmlSecEvents = entry.getValue();
+ while (!xmlSecEvents.isEmpty()) {
+ XMLSecEvent event = xmlSecEvents.pop();
+ subOutputProcessorChain.reset();
+ subOutputProcessorChain.processEvent(event);
+ }
+ //remove the actual header so that it won't be outputted twice
in the loop below
+ entryIterator.remove();
+ }
+ //... the action is encryption and...
+ if (entry.getKey().getAction().getName().contains("Encrypt")) {
+ encryptAction = true;
+ }
+ }
+ //...output the rest of the encrypt action and...
+ if (encryptAction) {
+ break loop;
+ }
+ }
+ //...loop again over the headers and output the leftover headers
+ iterator = actionEventMap.entrySet().iterator();
+ while (iterator.hasNext()) {
+ Map.Entry<XMLSecurityConstants.Action, Map<SecurityHeaderOrder,
Deque<XMLSecEvent>>> next = iterator.next();
+ Iterator<Map.Entry<SecurityHeaderOrder, Deque<XMLSecEvent>>>
entryIterator = next.getValue().entrySet().iterator();
+ while (entryIterator.hasNext()) {
+ Map.Entry<SecurityHeaderOrder, Deque<XMLSecEvent>> entry
= entryIterator.next();
Deque<XMLSecEvent> xmlSecEvents = entry.getValue();
while (!xmlSecEvents.isEmpty()) {
XMLSecEvent event = xmlSecEvents.pop();
@@ -129,24 +159,9 @@ public class SecurityHeaderReorderProces
" but got " + xmlSecStartElement.getName());
}
- Map<QName, Deque<XMLSecEvent>> map = null;
- if (!securityHeaderOrder.isEncrypted()) {
- map = actionEventMap.get(securityHeaderOrder.getAction());
- } else {
- Iterator<Map.Entry<XMLSecurityConstants.Action, Map<QName,
Deque<XMLSecEvent>>>> iterator = actionEventMap.entrySet().iterator();
- while (iterator.hasNext()) {
- Map.Entry<XMLSecurityConstants.Action, Map<QName, Deque<XMLSecEvent>>>
next = iterator.next();
- if (next.getKey().getName().contains("Encrypt")) {
- map = next.getValue();
- break;
- }
- }
- if (map == null) {
- throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE,
"empty", "No encrypt action found");
- }
- }
+ Map<SecurityHeaderOrder, Deque<XMLSecEvent>> map = actionEventMap.get(securityHeaderOrder.getAction());
currentDeque = new ArrayDeque<XMLSecEvent>();
- map.put(securityHeaderOrder.getSecurityHeaderElementName(), currentDeque);
+ map.put(securityHeaderOrder, currentDeque);
securityHeaderIndex++;
break;
Modified: webservices/wss4j/trunk/ws-security-stax/src/test/java/org/apache/wss4j/stax/test/HeaderOrderingTest.java
URL: http://svn.apache.org/viewvc/webservices/wss4j/trunk/ws-security-stax/src/test/java/org/apache/wss4j/stax/test/HeaderOrderingTest.java?rev=1491556&r1=1491555&r2=1491556&view=diff
==============================================================================
--- webservices/wss4j/trunk/ws-security-stax/src/test/java/org/apache/wss4j/stax/test/HeaderOrderingTest.java
(original)
+++ webservices/wss4j/trunk/ws-security-stax/src/test/java/org/apache/wss4j/stax/test/HeaderOrderingTest.java
Mon Jun 10 18:25:45 2013
@@ -665,4 +665,74 @@ public class HeaderOrderingTest extends
doInboundSecurityWithWSS4J_1(documentBuilderFactory.newDocumentBuilder().parse(new
ByteArrayInputStream(baos.toByteArray())), action, properties, true);
}
}
+
+ @Test
+ public void testUsernameTokenPlusTimestampPlusSignatureWithBSTSignedAndEncryptedStrictHeaderOrdering()
throws Exception {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+
+ {
+ WSSSecurityProperties securityProperties = new WSSSecurityProperties();
+ WSSConstants.Action[] actions = new WSSConstants.Action[]{WSSConstants.SIGNATURE,
WSSConstants.ENCRYPT, WSSConstants.USERNAMETOKEN, WSSConstants.TIMESTAMP};
+ securityProperties.setOutAction(actions);
+ securityProperties.loadSignatureKeyStore(this.getClass().getClassLoader().getResource("transmitter.jks"),
"default".toCharArray());
+ securityProperties.setSignatureUser("transmitter");
+ securityProperties.setTokenUser("transmitter");
+ securityProperties.setCallbackHandler(new CallbackHandlerImpl());
+ securityProperties.setSignatureKeyIdentifier(WSSecurityTokenConstants.KeyIdentifier_SecurityTokenDirectReference);
+ securityProperties.addSignaturePart(
+ new SecurePart(new QName(WSSConstants.NS_WSSE10, "UsernameToken"), SecurePart.Modifier.Element)
+ );
+ securityProperties.addSignaturePart(
+ new SecurePart(new QName(WSSConstants.NS_WSU10, "Timestamp"), SecurePart.Modifier.Element)
+ );
+ securityProperties.addSignaturePart(
+ new SecurePart(new QName(WSSConstants.NS_SOAP11, "Body"), SecurePart.Modifier.Element)
+ );
+
+ securityProperties.setEncryptionUser("receiver");
+ securityProperties.loadEncryptionKeystore(this.getClass().getClassLoader().getResource("transmitter.jks"),
"default".toCharArray());
+ securityProperties.setEncryptionKeyIdentifier(WSSecurityTokenConstants.KeyIdentifier_SecurityTokenDirectReference);
+ securityProperties.addEncryptionPart(
+ new SecurePart(new QName(WSSConstants.NS_DSIG, "Signature"), SecurePart.Modifier.Element)
+ );
+ securityProperties.addEncryptionPart(
+ new SecurePart(new QName(WSSConstants.NS_WSSE10, "UsernameToken"), SecurePart.Modifier.Element)
+ );
+ securityProperties.addEncryptionPart(
+ new SecurePart(new QName(WSSConstants.NS_WSU10, "Timestamp"), SecurePart.Modifier.Element)
+ );
+ securityProperties.addEncryptionPart(
+ new SecurePart(new QName(WSSConstants.NS_SOAP11, "Body"), SecurePart.Modifier.Content)
+ );
+
+ OutboundWSSec wsSecOut = WSSec.getOutboundWSSec(securityProperties);
+ XMLStreamWriter xmlStreamWriter = wsSecOut.processOutMessage(baos, "UTF-8", new
ArrayList<SecurityEvent>());
+ XMLStreamReader xmlStreamReader = xmlInputFactory.createXMLStreamReader(this.getClass().getClassLoader().getResourceAsStream("testdata/plain-soap-1.1.xml"));
+ XmlReaderToWriter.writeAll(xmlStreamReader, xmlStreamWriter);
+ xmlStreamWriter.close();
+
+ Document document = documentBuilderFactory.newDocumentBuilder().parse(new ByteArrayInputStream(baos.toByteArray()));
+
+ NodeList securityHeaderElement = document.getElementsByTagNameNS(WSConstants.WSSE_NS,
"Security");
+ Assert.assertEquals(1, securityHeaderElement.getLength());
+ NodeList childs = securityHeaderElement.item(0).getChildNodes();
+
+ Assert.assertEquals(childs.getLength(), 6);
+ Assert.assertEquals(childs.item(0).getLocalName(), "BinarySecurityToken");
+ Assert.assertEquals(childs.item(1).getLocalName(), "EncryptedKey");
+ Assert.assertEquals(childs.item(2).getLocalName(), "EncryptedData");
+ Assert.assertEquals(childs.item(3).getLocalName(), "EncryptedData");
+ Assert.assertEquals(childs.item(4).getLocalName(), "BinarySecurityToken");
+ Assert.assertEquals(childs.item(5).getLocalName(), "EncryptedData");
+
+ NodeList sigReferences = document.getElementsByTagNameNS(WSConstants.SIG_NS,
"Reference");
+ Assert.assertEquals(0, sigReferences.getLength()); //0 because the signature
is encrypted
+ }
+
+ //done UsernameToken; now verification:
+ {
+ String action = WSHandlerConstants.SIGNATURE + " " + WSHandlerConstants.USERNAME_TOKEN
+ " " + WSHandlerConstants.TIMESTAMP + " " + WSHandlerConstants.ENCRYPT;
+ doInboundSecurityWithWSS4J(documentBuilderFactory.newDocumentBuilder().parse(new
ByteArrayInputStream(baos.toByteArray())), action);
+ }
+ }
}
|