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.handler;
21  
22  import org.apache.ws.security.WSConstants;
23  import org.apache.ws.security.WSSConfig;
24  import org.apache.ws.security.WSSecurityEngine;
25  import org.apache.ws.security.WSSecurityEngineResult;
26  import org.apache.ws.security.WSSecurityException;
27  import org.apache.ws.security.common.CustomHandler;
28  import org.apache.ws.security.common.KeystoreCallbackHandler;
29  import org.apache.ws.security.common.SOAPUtil;
30  import org.apache.ws.security.components.crypto.Crypto;
31  import org.apache.ws.security.components.crypto.CryptoFactory;
32  import org.apache.ws.security.message.WSSecHeader;
33  import org.apache.ws.security.message.token.SignatureConfirmation;
34  import org.apache.ws.security.util.Base64;
35  import org.apache.ws.security.util.WSSecurityUtil;
36  import org.w3c.dom.Document;
37  import org.w3c.dom.Element;
38  
39  import java.util.List;
40  import java.util.ArrayList;
41  
42  import javax.security.auth.callback.CallbackHandler;
43  
44  /**
45   * A set of test-cases for SignatureConfirmation.
46   */
47  public class SignatureConfirmationTest extends org.junit.Assert {
48      private static final org.apache.commons.logging.Log LOG = 
49          org.apache.commons.logging.LogFactory.getLog(SignatureConfirmationTest.class);
50      private WSSecurityEngine secEngine = new WSSecurityEngine();
51      private CallbackHandler callbackHandler = new KeystoreCallbackHandler();
52      private Crypto crypto = null;
53      
54      public SignatureConfirmationTest() throws Exception {
55          crypto = CryptoFactory.getInstance();
56      }
57  
58      /**
59       * Test to see that a signature is saved correctly on the outbound request.
60       */
61      @SuppressWarnings("unchecked")
62      @org.junit.Test
63      public void
64      testRequestSavedSignature() throws Exception {
65          final RequestData reqData = new RequestData();
66          java.util.Map<String, Object> msgContext = new java.util.TreeMap<String, Object>();
67          msgContext.put(WSHandlerConstants.ENABLE_SIGNATURE_CONFIRMATION, "true");
68          msgContext.put(WSHandlerConstants.SIG_PROP_FILE, "crypto.properties");
69          msgContext.put("password", "security");
70          reqData.setMsgContext(msgContext);
71          reqData.setUsername("16c73ab6-b892-458f-abf5-2f875f74882e");
72          
73          final java.util.List<Integer> actions = new java.util.ArrayList<Integer>();
74          actions.add(Integer.valueOf(WSConstants.SIGN));
75          final Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
76          CustomHandler handler = new CustomHandler();
77          handler.send(
78              WSConstants.SIGN, doc, reqData, actions, true
79          );
80          if (LOG.isDebugEnabled()) {
81              LOG.debug("After Signing....");
82              String outputString = 
83                  org.apache.ws.security.util.XMLUtils.PrettyDocumentToString(doc);
84              LOG.debug(outputString);
85          }
86  
87          msgContext = (java.util.Map<String, Object>)reqData.getMsgContext();
88          List<byte[]> savedSignatures = 
89              (List<byte[]>)msgContext.get(WSHandlerConstants.SEND_SIGV);
90          assertTrue(savedSignatures != null && savedSignatures.size() == 1);
91          byte[] signatureValue = (byte[])savedSignatures.get(0);
92          assertTrue(signatureValue != null && signatureValue.length > 0);
93      }
94      
95      
96      /**
97       * Test to see that a signature is not saved on the outbound request if
98       * enable signature confirmation is false.
99       */
100     @SuppressWarnings("unchecked")
101     @org.junit.Test
102     public void
103     testRequestNotSavedSignature() throws Exception {
104         final RequestData reqData = new RequestData();
105         java.util.Map<String, Object> msgContext = new java.util.TreeMap<String, Object>();
106         msgContext.put(WSHandlerConstants.ENABLE_SIGNATURE_CONFIRMATION, "false");
107         msgContext.put(WSHandlerConstants.SIG_PROP_FILE, "crypto.properties");
108         msgContext.put("password", "security");
109         reqData.setMsgContext(msgContext);
110         reqData.setUsername("16c73ab6-b892-458f-abf5-2f875f74882e");
111         
112         final java.util.List<Integer> actions = new java.util.ArrayList<Integer>();
113         actions.add(Integer.valueOf(WSConstants.SIGN));
114         final Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
115         CustomHandler handler = new CustomHandler();
116         handler.send(
117             WSConstants.SIGN, doc, reqData, actions, true
118         );
119         if (LOG.isDebugEnabled()) {
120             LOG.debug("After Signing....");
121             String outputString = 
122                 org.apache.ws.security.util.XMLUtils.PrettyDocumentToString(doc);
123             LOG.debug(outputString);
124         }
125 
126         msgContext = (java.util.Map<String, Object>)reqData.getMsgContext();
127         List<byte[]> savedSignatures = 
128             (List<byte[]>)msgContext.get(WSHandlerConstants.SEND_SIGV);
129         assertTrue(savedSignatures == null);
130     }
131     
132     
133     /**
134      * Test to see that a signature confirmation response is correctly sent on receiving
135      * a signed message.
136      */
137     @SuppressWarnings("unchecked")
138     @org.junit.Test
139     public void
140     testSignatureConfirmationResponse() throws Exception {
141         final RequestData reqData = new RequestData();
142         java.util.Map<String, Object> msgContext = new java.util.TreeMap<String, Object>();
143         msgContext.put(WSHandlerConstants.ENABLE_SIGNATURE_CONFIRMATION, "true");
144         msgContext.put(WSHandlerConstants.SIG_PROP_FILE, "crypto.properties");
145         msgContext.put("password", "security");
146         reqData.setMsgContext(msgContext);
147         reqData.setUsername("16c73ab6-b892-458f-abf5-2f875f74882e");
148         
149         final java.util.List<Integer> actions = new java.util.ArrayList<Integer>();
150         actions.add(Integer.valueOf(WSConstants.SIGN));
151         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
152         CustomHandler handler = new CustomHandler();
153         handler.send(
154             WSConstants.SIGN, doc, reqData, actions, true
155         );
156         if (LOG.isDebugEnabled()) {
157             LOG.debug("After Signing....");
158             String outputString = 
159                 org.apache.ws.security.util.XMLUtils.PrettyDocumentToString(doc);
160             LOG.debug(outputString);
161         }
162 
163         msgContext = (java.util.Map<String, Object>)reqData.getMsgContext();
164         List<byte[]> savedSignatures = 
165             (List<byte[]>)msgContext.get(WSHandlerConstants.SEND_SIGV);
166         assertTrue(savedSignatures != null && savedSignatures.size() == 1);
167         byte[] signatureValue = (byte[])savedSignatures.get(0);
168         assertTrue(signatureValue != null && signatureValue.length > 0);
169         
170         //
171         // Verify the inbound request, and create a response with a Signature Confirmation
172         //
173         List<WSSecurityEngineResult> results = verify(doc);
174         actions.clear();
175         doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
176         msgContext = (java.util.Map<String, Object>)reqData.getMsgContext();
177         WSHandlerResult handlerResult = new WSHandlerResult(null, results);
178         List<WSHandlerResult> receivedResults = new ArrayList<WSHandlerResult>();
179         receivedResults.add(handlerResult);
180         msgContext.put(WSHandlerConstants.RECV_RESULTS, receivedResults);
181         handler.send(
182             WSConstants.NO_SECURITY, doc, reqData, actions, false
183         );
184         String outputString = 
185             org.apache.ws.security.util.XMLUtils.PrettyDocumentToString(doc);
186         if (LOG.isDebugEnabled()) {
187             LOG.debug("Signature Confirmation response....");
188             LOG.debug(outputString);
189         }
190         assertTrue(outputString.indexOf("SignatureConfirmation") != -1);
191         assertTrue(outputString.indexOf(Base64.encode(signatureValue)) != -1);
192     }
193     
194     
195     /**
196      * Test to see that a signature confirmation response is correctly processed.
197      */
198     @SuppressWarnings("unchecked")
199     @org.junit.Test
200     public void
201     testSignatureConfirmationProcessing() throws Exception {
202         final RequestData reqData = new RequestData();
203         java.util.Map<String, Object> msgContext = new java.util.TreeMap<String, Object>();
204         msgContext.put(WSHandlerConstants.ENABLE_SIGNATURE_CONFIRMATION, "true");
205         msgContext.put(WSHandlerConstants.SIG_PROP_FILE, "crypto.properties");
206         msgContext.put("password", "security");
207         reqData.setMsgContext(msgContext);
208         reqData.setUsername("16c73ab6-b892-458f-abf5-2f875f74882e");
209         
210         final java.util.List<Integer> actions = new java.util.ArrayList<Integer>();
211         actions.add(Integer.valueOf(WSConstants.SIGN));
212         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
213         CustomHandler handler = new CustomHandler();
214         handler.send(
215             WSConstants.SIGN, doc, reqData, actions, true
216         );
217         if (LOG.isDebugEnabled()) {
218             LOG.debug("After Signing....");
219             String outputString = 
220                 org.apache.ws.security.util.XMLUtils.PrettyDocumentToString(doc);
221             LOG.debug(outputString);
222         }
223 
224         //
225         // Verify the inbound request, and create a response with a Signature Confirmation
226         //
227         List<WSSecurityEngineResult> results = verify(doc);
228         actions.clear();
229         doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
230         msgContext = (java.util.Map<String, Object>)reqData.getMsgContext();
231         WSHandlerResult handlerResult = new WSHandlerResult(null, results);
232         List<WSHandlerResult> receivedResults = new ArrayList<WSHandlerResult>();
233         receivedResults.add(handlerResult);
234         msgContext.put(WSHandlerConstants.RECV_RESULTS, receivedResults);
235         handler.send(
236             WSConstants.NO_SECURITY, doc, reqData, actions, false
237         );
238         String outputString = 
239             org.apache.ws.security.util.XMLUtils.PrettyDocumentToString(doc);
240         if (LOG.isDebugEnabled()) {
241             LOG.debug("Signature Confirmation response....");
242             LOG.debug(outputString);
243         }
244         
245         //
246         // Verify the SignatureConfirmation response
247         //
248         results = verify(doc);
249         WSSecurityEngineResult scResult = 
250             WSSecurityUtil.fetchActionResult(results, WSConstants.SC);
251         assertTrue(scResult != null);
252         assertTrue(scResult.get(WSSecurityEngineResult.TAG_SIGNATURE_CONFIRMATION) != null);
253         handler.signatureConfirmation(reqData, results);
254     }
255     
256     
257     /**
258      * Test to see that a signature confirmation response that does not contain a wsu:Id fails
259      * the BSP compliance is enabled.
260      */
261     @org.junit.Test
262     public void
263     testWsuId() throws Exception {
264         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
265         WSSecHeader secHeader = new WSSecHeader();
266         secHeader.insertSecurityHeader(doc);
267         
268         byte[] randomBytes = WSSecurityUtil.generateNonce(20);
269         SignatureConfirmation sigConf = new SignatureConfirmation(doc, randomBytes);
270         Element sigConfElement = sigConf.getElement();
271         secHeader.getSecurityHeader().appendChild(sigConfElement);
272         
273         if (LOG.isDebugEnabled()) {
274             String outputString = 
275                 org.apache.ws.security.util.XMLUtils.PrettyDocumentToString(doc);
276             LOG.debug(outputString);
277         }
278         
279         // Verify the results
280         
281         // Turn off BSP spec compliance
282         WSSecurityEngine newEngine = new WSSecurityEngine();
283         WSSConfig config = WSSConfig.getNewInstance();
284         config.setWsiBSPCompliant(false);
285         newEngine.setWssConfig(config);
286         newEngine.processSecurityHeader(doc, null, callbackHandler, crypto);
287         
288         // Now turn on BSP spec compliance
289         config.setWsiBSPCompliant(true);
290         newEngine.setWssConfig(config);
291         try {
292             newEngine.processSecurityHeader(doc, null, callbackHandler, crypto);
293             fail("Failure expected on a request with no wsu:Id");
294         } catch (WSSecurityException ex) {
295             assertTrue(ex.getMessage().contains("wsu:Id"));
296         }
297     }
298     
299     
300     /**
301      * Verifies the soap envelope
302      * <p/>
303      * 
304      * @param doc 
305      * @throws Exception Thrown when there is a problem in verification
306      */
307     private List<WSSecurityEngineResult> verify(Document doc) throws Exception {
308         List<WSSecurityEngineResult> results = 
309             secEngine.processSecurityHeader(doc, null, callbackHandler, crypto);
310         if (LOG.isDebugEnabled()) {
311             LOG.debug("Verfied and decrypted message:");
312             String outputString = 
313                 org.apache.ws.security.util.XMLUtils.PrettyDocumentToString(doc);
314             LOG.debug(outputString);
315         }
316         return results;
317     }
318     
319 }