View Javadoc
1   /**
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements. See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership. The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License. You may obtain a copy of the License at
9    *
10   * http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied. See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.wss4j.stax.test;
20  
21  import java.io.ByteArrayInputStream;
22  import java.io.ByteArrayOutputStream;
23  import java.io.InputStream;
24  import java.nio.file.Path;
25  import java.util.Properties;
26  
27  import javax.xml.stream.XMLStreamException;
28  import javax.xml.stream.XMLStreamReader;
29  import javax.xml.transform.dom.DOMSource;
30  import javax.xml.transform.stream.StreamResult;
31  
32  import org.apache.wss4j.common.cache.EHCacheReplayCache;
33  import org.apache.wss4j.common.cache.ReplayCache;
34  import org.apache.wss4j.common.ext.WSSecurityException;
35  import org.apache.wss4j.common.saml.bean.ConditionsBean;
36  import org.apache.wss4j.common.saml.builder.SAML2Constants;
37  import org.apache.wss4j.dom.WSConstants;
38  import org.apache.wss4j.dom.handler.WSHandlerConstants;
39  import org.apache.wss4j.stax.ext.WSSConstants;
40  import org.apache.wss4j.stax.ext.WSSSecurityProperties;
41  import org.apache.wss4j.stax.setup.InboundWSSec;
42  import org.apache.wss4j.stax.setup.WSSec;
43  import org.apache.wss4j.stax.test.saml.SAML2CallbackHandler;
44  import org.apache.wss4j.stax.test.utils.StAX2DOM;
45  import org.apache.wss4j.stax.validate.SamlTokenValidatorImpl;
46  import org.apache.xml.security.exceptions.XMLSecurityException;
47  import org.junit.jupiter.api.Test;
48  import org.junit.jupiter.api.io.TempDir;
49  import org.w3c.dom.Document;
50  import org.w3c.dom.NodeList;
51  
52  import static org.junit.jupiter.api.Assertions.assertEquals;
53  import static org.junit.jupiter.api.Assertions.assertNotNull;
54  import static org.junit.jupiter.api.Assertions.assertTrue;
55  import static org.junit.jupiter.api.Assertions.fail;
56  
57  public class ReplayTest extends AbstractTestBase {
58  
59      @TempDir
60      Path tempDir;
61  
62      private ReplayCache createCache(String key) throws WSSecurityException {
63          try {
64              return new EHCacheReplayCache(key, tempDir);
65          } catch (XMLSecurityException e) {
66              throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, e);
67          }
68      }
69  
70      @Test
71      public void testReplayedTimestamp() throws Exception {
72  
73          ByteArrayOutputStream baos = new ByteArrayOutputStream();
74          {
75              InputStream sourceDocument = this.getClass().getClassLoader().getResourceAsStream("testdata/plain-soap-1.1.xml");
76              String action = WSHandlerConstants.SIGNATURE + " " + WSHandlerConstants.TIMESTAMP;
77              Properties properties = new Properties();
78              properties.setProperty(WSHandlerConstants.SIGNATURE_PARTS, "{Element}{" + WSConstants.WSU_NS + "}Timestamp;");
79              Document securedDocument = doOutboundSecurityWithWSS4J(sourceDocument, action, properties);
80  
81              //some test that we can really sure we get what we want from WSS4J
82              NodeList nodeList = securedDocument.getElementsByTagNameNS(WSSConstants.TAG_dsig_Signature.getNamespaceURI(), WSSConstants.TAG_dsig_Signature.getLocalPart());
83              assertEquals(nodeList.item(0).getParentNode().getLocalName(), WSSConstants.TAG_WSSE_SECURITY.getLocalPart());
84  
85              javax.xml.transform.Transformer transformer = TRANSFORMER_FACTORY.newTransformer();
86              transformer.transform(new DOMSource(securedDocument), new StreamResult(baos));
87          }
88  
89          //done signature; now test sig-verification:
90          ReplayCache replayCache = createCache("wss4j.timestamp.cache-");
91          {
92              WSSSecurityProperties securityProperties = new WSSSecurityProperties();
93              securityProperties.setTimestampReplayCache(replayCache);
94              securityProperties.loadSignatureVerificationKeystore(this.getClass().getClassLoader().getResource("receiver.jks"), "default".toCharArray());
95              InboundWSSec wsSecIn = WSSec.getInboundWSSec(securityProperties);
96              XMLStreamReader xmlStreamReader = wsSecIn.processInMessage(xmlInputFactory.createXMLStreamReader(new ByteArrayInputStream(baos.toByteArray())));
97  
98              Document document = StAX2DOM.readDoc(documentBuilderFactory.newDocumentBuilder(), xmlStreamReader);
99  
100             //header element must still be there
101             NodeList nodeList = document.getElementsByTagNameNS(WSSConstants.TAG_dsig_Signature.getNamespaceURI(), WSSConstants.TAG_dsig_Signature.getLocalPart());
102             assertEquals(nodeList.getLength(), 1);
103             assertEquals(nodeList.item(0).getParentNode().getLocalName(), WSSConstants.TAG_WSSE_SECURITY.getLocalPart());
104         }
105 
106         //done signature; now test sig-verification:
107         {
108             WSSSecurityProperties securityProperties = new WSSSecurityProperties();
109             securityProperties.setTimestampReplayCache(replayCache);
110             securityProperties.loadSignatureVerificationKeystore(this.getClass().getClassLoader().getResource("receiver.jks"), "default".toCharArray());
111             InboundWSSec wsSecIn = WSSec.getInboundWSSec(securityProperties, false, true);
112             XMLStreamReader xmlStreamReader = wsSecIn.processInMessage(xmlInputFactory.createXMLStreamReader(new ByteArrayInputStream(baos.toByteArray())));
113 
114             try {
115                 StAX2DOM.readDoc(documentBuilderFactory.newDocumentBuilder(), xmlStreamReader);
116                 fail("Exception expected");
117             } catch (XMLStreamException e) {
118                 assertTrue(e.getCause() instanceof XMLSecurityException);
119                 assertEquals("The message has expired", e.getCause().getMessage());
120             }
121         }
122 
123         replayCache.close();
124     }
125 
126     @Test
127     public void testUsernameToken() throws Exception {
128 
129         ByteArrayOutputStream baos = new ByteArrayOutputStream();
130         {
131             InputStream sourceDocument = this.getClass().getClassLoader().getResourceAsStream("testdata/plain-soap-1.1.xml");
132             String action = WSHandlerConstants.USERNAME_TOKEN;
133             Properties properties = new Properties();
134             Document securedDocument = doOutboundSecurityWithWSS4J(sourceDocument, action, properties);
135 
136             //some test that we can really sure we get what we want from WSS4J
137             NodeList nodeList = securedDocument.getElementsByTagNameNS(WSSConstants.TAG_WSSE_USERNAME_TOKEN.getNamespaceURI(), WSSConstants.TAG_WSSE_USERNAME_TOKEN.getLocalPart());
138             assertEquals(nodeList.item(0).getParentNode().getLocalName(), WSSConstants.TAG_WSSE_SECURITY.getLocalPart());
139 
140             javax.xml.transform.Transformer transformer = TRANSFORMER_FACTORY.newTransformer();
141             transformer.transform(new DOMSource(securedDocument), new StreamResult(baos));
142         }
143 
144         //done UsernameToken; now test verification:
145         ReplayCache replayCache = createCache("wss4j.nonce.cache-");
146         {
147             WSSSecurityProperties securityProperties = new WSSSecurityProperties();
148             securityProperties.setNonceReplayCache(replayCache);
149             securityProperties.setCallbackHandler(new CallbackHandlerImpl());
150             InboundWSSec wsSecIn = WSSec.getInboundWSSec(securityProperties);
151             XMLStreamReader xmlStreamReader = wsSecIn.processInMessage(xmlInputFactory.createXMLStreamReader(new ByteArrayInputStream(baos.toByteArray())));
152 
153             Document document = StAX2DOM.readDoc(documentBuilderFactory.newDocumentBuilder(), xmlStreamReader);
154 
155             //header element must still be there
156             NodeList nodeList = document.getElementsByTagNameNS(WSSConstants.TAG_WSSE_USERNAME_TOKEN.getNamespaceURI(), WSSConstants.TAG_WSSE_USERNAME_TOKEN.getLocalPart());
157             assertEquals(nodeList.getLength(), 1);
158             assertEquals(nodeList.item(0).getParentNode().getLocalName(), WSSConstants.TAG_WSSE_SECURITY.getLocalPart());
159         }
160 
161         //done UsernameToken; now test verification:
162         {
163             WSSSecurityProperties securityProperties = new WSSSecurityProperties();
164             securityProperties.setNonceReplayCache(replayCache);
165             securityProperties.setCallbackHandler(new CallbackHandlerImpl());
166             InboundWSSec wsSecIn = WSSec.getInboundWSSec(securityProperties);
167             XMLStreamReader xmlStreamReader = wsSecIn.processInMessage(xmlInputFactory.createXMLStreamReader(new ByteArrayInputStream(baos.toByteArray())));
168 
169             try {
170                 StAX2DOM.readDoc(documentBuilderFactory.newDocumentBuilder(), xmlStreamReader);
171                 fail("Exception expected");
172             } catch (XMLStreamException e) {
173                 assertTrue(e.getCause() instanceof XMLSecurityException);
174             }
175         }
176 
177         replayCache.close();
178     }
179 
180     /**
181      * Test that creates, sends and processes an unsigned SAML 2 authentication assertion. This
182      * is just a sanity test to make sure that it is possible to send the SAML token twice, as
183      * no "OneTimeUse" Element is defined there is no problem with replaying it.
184      * with a OneTimeUse Element
185      */
186     @Test
187     public void testEhCacheReplayedSAML2() throws Exception {
188         ByteArrayOutputStream baos = new ByteArrayOutputStream();
189         {
190             SAML2CallbackHandler callbackHandler = new SAML2CallbackHandler();
191             callbackHandler.setStatement(SAML2CallbackHandler.Statement.AUTHN);
192             callbackHandler.setConfirmationMethod(SAML2Constants.CONF_BEARER);
193             callbackHandler.setIssuer("www.example.com");
194             callbackHandler.setSignAssertion(false);
195 
196             ConditionsBean conditions = new ConditionsBean();
197             conditions.setTokenPeriodMinutes(5);
198             callbackHandler.setConditions(conditions);
199 
200             InputStream sourceDocument = this.getClass().getClassLoader().getResourceAsStream("testdata/plain-soap-1.1.xml");
201             String action = WSHandlerConstants.SAML_TOKEN_UNSIGNED;
202             Properties properties = new Properties();
203             properties.put(WSHandlerConstants.SAML_CALLBACK_REF, callbackHandler);
204             Document securedDocument = doOutboundSecurityWithWSS4J(sourceDocument, action, properties);
205 
206             javax.xml.transform.Transformer transformer = TRANSFORMER_FACTORY.newTransformer();
207             transformer.transform(new DOMSource(securedDocument), new StreamResult(baos));
208         }
209 
210         // process SAML Token
211         ReplayCache replayCache = createCache("wss4j.saml.one.time.use.cache-");
212         {
213             WSSSecurityProperties securityProperties = new WSSSecurityProperties();
214 
215             SamlTokenValidatorImpl validator = new SamlTokenValidatorImpl();
216             validator.setRequireBearerSignature(false);
217             securityProperties.addValidator(WSSConstants.TAG_SAML2_ASSERTION, validator);
218             securityProperties.addValidator(WSSConstants.TAG_SAML_ASSERTION, validator);
219 
220             securityProperties.setSamlOneTimeUseReplayCache(replayCache);
221             InboundWSSec wsSecIn = WSSec.getInboundWSSec(securityProperties);
222             XMLStreamReader xmlStreamReader = wsSecIn.processInMessage(xmlInputFactory.createXMLStreamReader(new ByteArrayInputStream(baos.toByteArray())));
223 
224             Document document = StAX2DOM.readDoc(documentBuilderFactory.newDocumentBuilder(), xmlStreamReader);
225             assertNotNull(document);
226         }
227 
228         // now process SAML Token again
229         {
230             WSSSecurityProperties securityProperties = new WSSSecurityProperties();
231 
232             SamlTokenValidatorImpl validator = new SamlTokenValidatorImpl();
233             validator.setRequireBearerSignature(false);
234             securityProperties.addValidator(WSSConstants.TAG_SAML2_ASSERTION, validator);
235             securityProperties.addValidator(WSSConstants.TAG_SAML_ASSERTION, validator);
236 
237             securityProperties.setSamlOneTimeUseReplayCache(replayCache);
238             InboundWSSec wsSecIn = WSSec.getInboundWSSec(securityProperties);
239             XMLStreamReader xmlStreamReader = wsSecIn.processInMessage(xmlInputFactory.createXMLStreamReader(new ByteArrayInputStream(baos.toByteArray())));
240 
241             Document document = StAX2DOM.readDoc(documentBuilderFactory.newDocumentBuilder(), xmlStreamReader);
242             assertNotNull(document);
243         }
244 
245         replayCache.close();
246     }
247 
248     /**
249      * Test that creates, sends and processes an unsigned SAML 2 authentication assertion
250      * with a OneTimeUse Element
251      */
252     @Test
253     public void testEhCacheReplayedSAML2OneTimeUse() throws Exception {
254         ByteArrayOutputStream baos = new ByteArrayOutputStream();
255         {
256             SAML2CallbackHandler callbackHandler = new SAML2CallbackHandler();
257             callbackHandler.setStatement(SAML2CallbackHandler.Statement.AUTHN);
258             callbackHandler.setConfirmationMethod(SAML2Constants.CONF_BEARER);
259             callbackHandler.setIssuer("www.example.com");
260             callbackHandler.setSignAssertion(false);
261 
262             ConditionsBean conditions = new ConditionsBean();
263             conditions.setTokenPeriodMinutes(5);
264             conditions.setOneTimeUse(true);
265             callbackHandler.setConditions(conditions);
266 
267             InputStream sourceDocument = this.getClass().getClassLoader().getResourceAsStream("testdata/plain-soap-1.1.xml");
268             String action = WSHandlerConstants.SAML_TOKEN_UNSIGNED;
269             Properties properties = new Properties();
270             properties.put(WSHandlerConstants.SAML_CALLBACK_REF, callbackHandler);
271             Document securedDocument = doOutboundSecurityWithWSS4J(sourceDocument, action, properties);
272 
273             javax.xml.transform.Transformer transformer = TRANSFORMER_FACTORY.newTransformer();
274             transformer.transform(new DOMSource(securedDocument), new StreamResult(baos));
275         }
276 
277         // process SAML Token
278         ReplayCache replayCache = createCache("wss4j.saml.one.time.use.cache-");
279         {
280             WSSSecurityProperties securityProperties = new WSSSecurityProperties();
281 
282             SamlTokenValidatorImpl validator = new SamlTokenValidatorImpl();
283             validator.setRequireBearerSignature(false);
284             securityProperties.addValidator(WSSConstants.TAG_SAML2_ASSERTION, validator);
285             securityProperties.addValidator(WSSConstants.TAG_SAML_ASSERTION, validator);
286 
287             securityProperties.setSamlOneTimeUseReplayCache(replayCache);
288             InboundWSSec wsSecIn = WSSec.getInboundWSSec(securityProperties);
289             XMLStreamReader xmlStreamReader = wsSecIn.processInMessage(xmlInputFactory.createXMLStreamReader(new ByteArrayInputStream(baos.toByteArray())));
290 
291             Document document = StAX2DOM.readDoc(documentBuilderFactory.newDocumentBuilder(), xmlStreamReader);
292             assertNotNull(document);
293         }
294 
295         // now process SAML Token again
296         {
297             WSSSecurityProperties securityProperties = new WSSSecurityProperties();
298 
299             SamlTokenValidatorImpl validator = new SamlTokenValidatorImpl();
300             validator.setRequireBearerSignature(false);
301             securityProperties.addValidator(WSSConstants.TAG_SAML2_ASSERTION, validator);
302             securityProperties.addValidator(WSSConstants.TAG_SAML_ASSERTION, validator);
303 
304             securityProperties.setSamlOneTimeUseReplayCache(replayCache);
305             InboundWSSec wsSecIn = WSSec.getInboundWSSec(securityProperties);
306             XMLStreamReader xmlStreamReader = wsSecIn.processInMessage(xmlInputFactory.createXMLStreamReader(new ByteArrayInputStream(baos.toByteArray())));
307 
308             try {
309                 StAX2DOM.readDoc(documentBuilderFactory.newDocumentBuilder(), xmlStreamReader);
310                 fail("Exception expected");
311             } catch (XMLStreamException e) {
312                 assertTrue(e.getCause() instanceof XMLSecurityException);
313             }
314         }
315 
316         replayCache.close();
317     }
318 
319 }