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  
20  package org.apache.ws.security.message;
21  
22  import java.text.MessageFormat;
23  import java.util.LinkedList;
24  import java.util.List;
25  import java.util.Map;
26  import java.util.ResourceBundle;
27  import java.util.TreeMap;
28  
29  import javax.security.auth.callback.CallbackHandler;
30  
31  import org.apache.ws.security.WSSConfig;
32  import org.apache.ws.security.WSSecurityEngine;
33  import org.apache.ws.security.WSSecurityEngineResult;
34  import org.apache.ws.security.WSSecurityException;
35  import org.apache.ws.security.common.CustomHandler;
36  import org.apache.ws.security.common.KeystoreCallbackHandler;
37  import org.apache.ws.security.common.SOAPUtil;
38  import org.apache.ws.security.components.crypto.Crypto;
39  import org.apache.ws.security.components.crypto.CryptoFactory;
40  import org.apache.ws.security.handler.RequestData;
41  import org.apache.ws.security.handler.WSHandlerConstants;
42  import org.apache.ws.security.util.WSSecurityUtil;
43  import org.w3c.dom.Document;
44  import org.w3c.dom.Element;
45  
46  /**
47   * Tests for the WSHandlerConstants.REQUIRE_SIGNED_ENCRYPTED_DATA_ELEMENTS option.
48   * This test verifies some wrapping techniques are properly handled when the afore
49   * mentioned option is on.
50   * 
51   * @author <a href="mailto:alessio.soldano@jboss.com">Alessio Soldano</a>
52   */
53  public class RequireSignedEncryptedDataElementsTest extends org.junit.Assert {
54      private static final org.apache.commons.logging.Log LOG = 
55          org.apache.commons.logging.LogFactory.getLog(RequireSignedEncryptedDataElementsTest.class);
56      private static ResourceBundle resources = ResourceBundle.getBundle("org.apache.ws.security.errors");
57      private static final String SOAPMSG = 
58          "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" 
59          + "<SOAP-ENV:Envelope "
60          +   "xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\" "
61          +   "xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" "
62          +   "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">" 
63          +   "<SOAP-ENV:Body>" 
64          +       "<add xmlns=\"http://ws.apache.org/counter/counter_port_type\">" 
65          +           "<value xmlns=\"http://blah.com\">15</value>" 
66          +       "</add>" 
67          +   "</SOAP-ENV:Body>" 
68          + "</SOAP-ENV:Envelope>";
69      private WSSecurityEngine secEngine = new WSSecurityEngine();
70      private CallbackHandler callbackHandler = new KeystoreCallbackHandler();
71      private Crypto crypto = null;
72  
73      
74      public RequireSignedEncryptedDataElementsTest() throws Exception {
75          crypto = CryptoFactory.getInstance();
76          WSSConfig.init();
77      }
78  
79      @org.junit.Test
80      public void testEncryptedKeyRefAndDuplicatedEncDataInWsseHeader() throws Exception {
81          Document encryptedSignedDoc = getRequestDocument();
82          RequestData reqData = getRequestData(true);
83          verify(encryptedSignedDoc, reqData);
84          
85          encryptedSignedDoc = getRequestDocument();
86          reqData = getRequestData(false);
87          TestMessageTransformer.duplicateEncryptedDataInWsseHeader(encryptedSignedDoc.getDocumentElement(), false);
88          verify(encryptedSignedDoc, reqData);
89          
90          encryptedSignedDoc = getRequestDocument();
91          reqData = getRequestData(true);
92          Element newEncData = TestMessageTransformer.duplicateEncryptedDataInWsseHeader(encryptedSignedDoc.getDocumentElement(), false);
93          try {
94              verify(encryptedSignedDoc, reqData);
95              fail("WSSecurityException expected");
96          } catch (WSSecurityException e) {
97              checkFailure(newEncData, e);
98          }
99      }
100     
101     @org.junit.Test
102     public void testEncryptedKeyRefAndDuplicatedEncDataInWsseWrapperHeader() throws Exception {
103         Document encryptedSignedDoc = getRequestDocument();
104         RequestData reqData = getRequestData(true);
105         verify(encryptedSignedDoc, reqData);
106         
107         encryptedSignedDoc = getRequestDocument();
108         reqData = getRequestData(false);
109         TestMessageTransformer.duplicateEncryptedDataInWsseWrapperHeader(encryptedSignedDoc.getDocumentElement(), false);
110         verify(encryptedSignedDoc, reqData);
111         
112         encryptedSignedDoc = getRequestDocument();
113         reqData = getRequestData(true);
114         Element newEncData = TestMessageTransformer.duplicateEncryptedDataInWsseWrapperHeader(encryptedSignedDoc.getDocumentElement(), false);
115         try {
116             verify(encryptedSignedDoc, reqData);
117             fail("WSSecurityException expected");
118         } catch (WSSecurityException e) {
119             checkFailure(newEncData, e);
120         }
121     }
122     
123     @org.junit.Test
124     public void testEncryptedKeyRefAndDuplicatedEncDataInExternalWrapperElement() throws Exception {
125         Document encryptedSignedDoc = getRequestDocument();
126         RequestData reqData = getRequestData(true);
127         verify(encryptedSignedDoc, reqData);
128         
129         encryptedSignedDoc = getRequestDocument();
130         reqData = getRequestData(false);
131         TestMessageTransformer.duplicateEncryptedDataInExternalWrapperElement(encryptedSignedDoc.getDocumentElement(), false);
132         verify(encryptedSignedDoc, reqData);
133         
134         encryptedSignedDoc = getRequestDocument();
135         reqData = getRequestData(true);
136         Element newEncData = TestMessageTransformer.duplicateEncryptedDataInExternalWrapperElement(encryptedSignedDoc.getDocumentElement(), false);
137         try {
138             verify(encryptedSignedDoc, reqData);
139             fail("WSSecurityException expected");
140         } catch (WSSecurityException e) {
141             checkFailure(newEncData, e);
142         }
143     }
144     
145     @org.junit.Test
146     public void testReferenceListAndDuplicatedEncDataInWsseHeader() throws Exception {
147         Document encryptedSignedDoc = getRequestDocument();
148         RequestData reqData = getRequestData(true);
149         verify(encryptedSignedDoc, reqData);
150         
151         encryptedSignedDoc = getRequestDocument();
152         reqData = getRequestData(false);
153         TestMessageTransformer.duplicateEncryptedDataInWsseHeader(encryptedSignedDoc.getDocumentElement(), true);
154         verify(encryptedSignedDoc, reqData);
155         
156         encryptedSignedDoc = getRequestDocument();
157         reqData = getRequestData(true);
158         Element newEncData = TestMessageTransformer.duplicateEncryptedDataInWsseHeader(encryptedSignedDoc.getDocumentElement(), true);
159         try {
160             verify(encryptedSignedDoc, reqData);
161             fail("WSSecurityException expected");
162         } catch (WSSecurityException e) {
163             checkFailure(newEncData, e);
164         }
165     }
166     
167     @org.junit.Test
168     public void testReferenceListAndDuplicatedEncDataInWsseWrapperHeader() throws Exception {
169         Document encryptedSignedDoc = getRequestDocument();
170         RequestData reqData = getRequestData(true);
171         verify(encryptedSignedDoc, reqData);
172         
173         encryptedSignedDoc = getRequestDocument();
174         reqData = getRequestData(false);
175         TestMessageTransformer.duplicateEncryptedDataInWsseWrapperHeader(encryptedSignedDoc.getDocumentElement(), true);
176         verify(encryptedSignedDoc, reqData);
177         
178         encryptedSignedDoc = getRequestDocument();
179         reqData = getRequestData(true);
180         Element newEncData = TestMessageTransformer.duplicateEncryptedDataInWsseWrapperHeader(encryptedSignedDoc.getDocumentElement(), true);
181         try {
182             verify(encryptedSignedDoc, reqData);
183             fail("WSSecurityException expected");
184         } catch (WSSecurityException e) {
185             checkFailure(newEncData, e);
186         }
187     }
188     
189     @org.junit.Test
190     public void testReferenceListAndDuplicatedEncDataInExternalWrapperElement() throws Exception {
191         Document encryptedSignedDoc = getRequestDocument();
192         RequestData reqData = getRequestData(true);
193         verify(encryptedSignedDoc, reqData);
194         
195         encryptedSignedDoc = getRequestDocument();
196         reqData = getRequestData(false);
197         TestMessageTransformer.duplicateEncryptedDataInExternalWrapperElement(encryptedSignedDoc.getDocumentElement(), true);
198         verify(encryptedSignedDoc, reqData);
199         
200         encryptedSignedDoc = getRequestDocument();
201         reqData = getRequestData(true);
202         Element newEncData = TestMessageTransformer.duplicateEncryptedDataInExternalWrapperElement(encryptedSignedDoc.getDocumentElement(), true);
203         try {
204             verify(encryptedSignedDoc, reqData);
205             fail("WSSecurityException expected");
206         } catch (WSSecurityException e) {
207             checkFailure(newEncData, e);
208         }
209     }
210     
211     @org.junit.Test
212     public void testAdditionalEncryptedDataWithEmbeddedEncryptedKeyInWsseHeader() throws Exception {
213         Document encryptedSignedDoc = getRequestDocument();
214         RequestData reqData = getRequestData(true);
215         verify(encryptedSignedDoc, reqData);
216         
217         encryptedSignedDoc = getRequestDocument();
218         reqData = getRequestData(true);
219         Element newEncData = TestMessageTransformer.addEncryptedDataWithEmbeddedEncryptedKeyInWsseHeader(encryptedSignedDoc.getDocumentElement());
220         try {
221             verify(encryptedSignedDoc, reqData);
222             fail("WSSecurityException expected");
223         } catch (WSSecurityException e) {
224             checkFailure(newEncData, e);
225         }
226     }
227     
228     private static void checkFailure(Element attackElement, WSSecurityException e) {
229         final String mex = MessageFormat.format(resources.getString("requiredElementNotSigned"), attackElement);
230         assertTrue(e.getMessage().contains(mex));
231         assertEquals(WSSecurityException.FAILED_CHECK, e.getErrorCode());
232     }
233     
234     private RequestData getRequestData(boolean reqSignedEncData) throws WSSecurityException {
235         RequestData reqData = new RequestData();
236         Map<String, Object> messageContext = new TreeMap<String, Object>();
237         messageContext = new java.util.TreeMap<String, Object>();
238         messageContext.put(WSHandlerConstants.REQUIRE_SIGNED_ENCRYPTED_DATA_ELEMENTS, Boolean.toString(reqSignedEncData));
239         reqData.setMsgContext(messageContext);
240         CustomHandler handler = new CustomHandler();
241         handler.receive(WSSecurityUtil.decodeAction("Encrypt Signature", new LinkedList<Integer>()), reqData);
242         reqData.setCallbackHandler(callbackHandler);
243         reqData.setSigCrypto(crypto);
244         reqData.setDecCrypto(crypto);
245         return reqData;
246     }
247     
248     private Document getRequestDocument() throws Exception {
249         WSSecEncrypt encrypt = new WSSecEncrypt();
250         WSSecSignature sign = new WSSecSignature();
251         encrypt.setUserInfo("16c73ab6-b892-458f-abf5-2f875f74882e");
252         sign.setUserInfo("16c73ab6-b892-458f-abf5-2f875f74882e", "security");
253         LOG.info("Before Encryption....");
254         Document doc = SOAPUtil.toSOAPPart(SOAPMSG);
255 
256         WSSecHeader secHeader = new WSSecHeader();
257         secHeader.insertSecurityHeader(doc);
258 
259         Document encryptedDoc = encrypt.build(doc, crypto, secHeader);
260         
261         if (LOG.isDebugEnabled()) {
262             LOG.debug("After Encryption....");
263             String outputString = 
264                 org.apache.ws.security.util.XMLUtils.PrettyDocumentToString(encryptedDoc);
265             LOG.debug(outputString);
266         }
267         
268         Document encryptedSignedDoc = sign.build(encryptedDoc, crypto, secHeader);
269         
270         if (LOG.isDebugEnabled()) {
271             LOG.debug("After Signing....");
272             String outputString = 
273                 org.apache.ws.security.util.XMLUtils.PrettyDocumentToString(encryptedSignedDoc);
274             LOG.debug(outputString);
275         }
276         return encryptedSignedDoc;
277     }
278 
279     
280     private List<WSSecurityEngineResult> verify(Document doc, RequestData reqData) throws Exception {
281         Element elem = WSSecurityUtil.getSecurityHeader(doc, null);
282         List<WSSecurityEngineResult> resultList = 
283             secEngine.processSecurityHeader(elem, reqData);
284         if (LOG.isDebugEnabled()) {
285             String outputString = 
286                 org.apache.ws.security.util.XMLUtils.PrettyDocumentToString(doc);
287             LOG.debug(outputString);
288         }
289         
290         return resultList;
291     }
292 
293 }