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.util.List;
23  
24  import javax.xml.crypto.dsig.SignatureMethod;
25  
26  import org.apache.ws.security.WSConstants;
27  import org.apache.ws.security.WSSecurityEngine;
28  import org.apache.ws.security.WSSecurityEngineResult;
29  import org.apache.ws.security.common.SecretKeyCallbackHandler;
30  import org.apache.ws.security.common.SOAPUtil;
31  import org.apache.ws.security.components.crypto.Crypto;
32  import org.apache.ws.security.components.crypto.CryptoFactory;
33  import org.apache.ws.security.conversation.ConversationConstants;
34  import org.apache.ws.security.message.token.SecurityContextToken;
35  import org.apache.ws.security.util.WSSecurityUtil;
36  import org.w3c.dom.Document;
37  
38  /**
39   * A set of tests for SecurityContextTokens.
40   * 
41   * @author Ruchith Fernando (ruchith.fernando@gmail.com)
42   */
43  public class SecurityContextTokenTest extends org.junit.Assert {
44      private static final org.apache.commons.logging.Log LOG = 
45          org.apache.commons.logging.LogFactory.getLog(SecurityContextTokenTest.class);
46      private WSSecurityEngine secEngine = new WSSecurityEngine();
47      private SecretKeyCallbackHandler callbackHandler = new SecretKeyCallbackHandler();
48      private Crypto crypto = null;
49      
50      public SecurityContextTokenTest() throws Exception {
51          crypto = CryptoFactory.getInstance("wss40.properties");
52      }
53  
54      @org.junit.Test
55      public void testBuild() {
56          try {
57              Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
58              WSSecHeader secHeader = new WSSecHeader();
59              secHeader.insertSecurityHeader(doc);
60  
61              WSSecSecurityContextToken sctBuilder = new WSSecSecurityContextToken();
62              sctBuilder.prepare(doc, crypto);
63              
64              sctBuilder.prependSCTElementToHeader(doc, secHeader);
65  
66              String out = 
67                  org.apache.ws.security.util.XMLUtils.PrettyDocumentToString(doc);
68              
69              if (LOG.isDebugEnabled()) {
70                  LOG.debug(out);
71              }
72  
73              assertTrue(
74                  "SecurityContextToken missing",
75                  out.indexOf(ConversationConstants.SECURITY_CONTEXT_TOKEN_LN) > 0
76              );
77              assertTrue(
78                  "wsc:Identifier missing", 
79                  out.indexOf(ConversationConstants.IDENTIFIER_LN) > 0
80              );
81  
82          } catch (Exception e) {
83              e.printStackTrace();
84              fail(e.getMessage());
85          }
86      }
87  
88      /**
89       * Test encryption using a derived key which is based on a secret associated
90       * with a security context token
91       */
92      @org.junit.Test
93      public void testSCTDKTEncrypt() {
94          try {
95              Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
96              WSSecHeader secHeader = new WSSecHeader();
97              secHeader.insertSecurityHeader(doc);
98  
99              WSSecSecurityContextToken sctBuilder = new WSSecSecurityContextToken();
100             sctBuilder.prepare(doc, crypto);
101 
102             byte[] tempSecret = WSSecurityUtil.generateNonce(16);
103 
104             // Store the secret
105             callbackHandler.addSecretKey(sctBuilder.getIdentifier(), tempSecret);
106 
107             String tokenId = sctBuilder.getSctId();
108 
109             // Derived key encryption
110             WSSecDKEncrypt encrBuilder = new WSSecDKEncrypt();
111             encrBuilder.setSymmetricEncAlgorithm(WSConstants.AES_128);
112             encrBuilder.setExternalKey(tempSecret, tokenId);
113             encrBuilder.build(doc, secHeader);
114 
115             sctBuilder.prependSCTElementToHeader(doc, secHeader);
116 
117             if (LOG.isDebugEnabled()) {
118                 String out = org.apache.ws.security.util.XMLUtils.PrettyDocumentToString(doc);
119                 LOG.debug(out);
120             }
121 
122             List<WSSecurityEngineResult> results = verify(doc);
123             
124             WSSecurityEngineResult actionResult =
125                 WSSecurityUtil.fetchActionResult(results, WSConstants.SCT);
126             SecurityContextToken receivedToken = 
127                 (SecurityContextToken) actionResult.get(WSSecurityEngineResult.TAG_SECURITY_CONTEXT_TOKEN);
128             assertTrue(receivedToken != null);
129             assertTrue(WSConstants.WSC_SCT.equals(receivedToken.getTokenType()));
130             
131             SecurityContextToken clone = new SecurityContextToken(receivedToken.getElement());
132             assertTrue(clone.equals(receivedToken));
133             assertTrue(clone.hashCode() == receivedToken.hashCode());
134             
135         } catch (Exception e) {
136             e.printStackTrace();
137             fail(e.getMessage());
138         }
139     }
140 
141     @org.junit.Test
142     public void testSCTKDKTSign() {
143         try {
144             Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
145             WSSecHeader secHeader = new WSSecHeader();
146             secHeader.insertSecurityHeader(doc);
147 
148             WSSecSecurityContextToken sctBuilder = new WSSecSecurityContextToken();
149             sctBuilder.setWscVersion(ConversationConstants.VERSION_05_12);
150             sctBuilder.prepare(doc, crypto);
151 
152             byte[] tempSecret = WSSecurityUtil.generateNonce(16);
153 
154             // Store the secret
155             callbackHandler.addSecretKey(sctBuilder.getIdentifier(), tempSecret);
156 
157             String tokenId = sctBuilder.getSctId();
158 
159             // Derived key signature
160             WSSecDKSign sigBuilder = new WSSecDKSign();
161             sigBuilder.setExternalKey(tempSecret, tokenId);
162             sigBuilder.setSignatureAlgorithm(WSConstants.HMAC_SHA1);
163             sigBuilder.build(doc, secHeader);
164             
165             sctBuilder.prependSCTElementToHeader(doc, secHeader);
166 
167             if (LOG.isDebugEnabled()) {
168                 String out = org.apache.ws.security.util.XMLUtils.PrettyDocumentToString(doc);
169                 LOG.debug(out);
170             }
171 
172             List<WSSecurityEngineResult> results = verify(doc);
173             
174             WSSecurityEngineResult actionResult =
175                 WSSecurityUtil.fetchActionResult(results, WSConstants.SCT);
176             SecurityContextToken receivedToken = 
177                 (SecurityContextToken) actionResult.get(WSSecurityEngineResult.TAG_SECURITY_CONTEXT_TOKEN);
178             assertTrue(receivedToken != null);
179             assertTrue(WSConstants.WSC_SCT_05_12.equals(receivedToken.getTokenType()));
180             
181         } catch (Exception e) {
182             e.printStackTrace();
183             fail(e.getMessage());
184         }
185     }
186     
187     /**
188      * Test for WSS-217:
189      * "Add ability to specify a reference to an absolute URI in the derived key functionality".
190      */
191     @org.junit.Test
192     public void testSCTKDKTSignAbsolute() {
193         try {
194             Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
195             WSSecHeader secHeader = new WSSecHeader();
196             secHeader.insertSecurityHeader(doc);
197 
198             WSSecSecurityContextToken sctBuilder = new WSSecSecurityContextToken();
199             sctBuilder.prepare(doc, crypto);
200 
201             byte[] tempSecret = WSSecurityUtil.generateNonce(16);
202 
203             // Store the secret
204             callbackHandler.addSecretKey(sctBuilder.getIdentifier(), tempSecret);
205 
206             // Derived key signature
207             WSSecDKSign sigBuilder = new WSSecDKSign();
208             sigBuilder.setExternalKey(tempSecret, sctBuilder.getIdentifier());
209             sigBuilder.setTokenIdDirectId(true);
210             sigBuilder.setSignatureAlgorithm(WSConstants.HMAC_SHA1);
211             sigBuilder.build(doc, secHeader);
212             
213             sctBuilder.prependSCTElementToHeader(doc, secHeader);
214 
215             if (LOG.isDebugEnabled()) {
216                 LOG.debug("DKT Absolute");
217                 String outputString = 
218                     org.apache.ws.security.util.XMLUtils.PrettyDocumentToString(doc);
219                 LOG.debug(outputString);
220             }
221 
222             verify(doc);
223         } catch (Exception e) {
224             e.printStackTrace();
225             fail(e.getMessage());
226         }
227     }
228 
229     @org.junit.Test
230     public void testSCTKDKTSignEncrypt() {
231         try {
232             Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
233             WSSecHeader secHeader = new WSSecHeader();
234             secHeader.insertSecurityHeader(doc);
235 
236             WSSecSecurityContextToken sctBuilder = new WSSecSecurityContextToken();
237             sctBuilder.prepare(doc, crypto);
238 
239             byte[] tempSecret = WSSecurityUtil.generateNonce(16);
240 
241             // Store the secret
242             callbackHandler.addSecretKey(sctBuilder.getIdentifier(), tempSecret);
243 
244             String tokenId = sctBuilder.getSctId();
245 
246             // Derived key signature
247             WSSecDKSign sigBuilder = new WSSecDKSign();
248             sigBuilder.setExternalKey(tempSecret, tokenId);
249             sigBuilder.setSignatureAlgorithm(WSConstants.HMAC_SHA1);
250             sigBuilder.build(doc, secHeader);
251 
252             // Derived key encryption
253             WSSecDKEncrypt encrBuilder = new WSSecDKEncrypt();
254             encrBuilder.setSymmetricEncAlgorithm(WSConstants.AES_128);
255             encrBuilder.setExternalKey(tempSecret, tokenId);
256             encrBuilder.build(doc, secHeader);
257 
258             sctBuilder.prependSCTElementToHeader(doc, secHeader);
259 
260             if (LOG.isDebugEnabled()) {
261                 String out = org.apache.ws.security.util.XMLUtils.PrettyDocumentToString(doc);
262                 LOG.debug(out);
263             }
264 
265             verify(doc);
266         } catch (Exception e) {
267             e.printStackTrace();
268             fail(e.getMessage());
269         }
270     }
271 
272     @org.junit.Test
273     public void testSCTKDKTEncryptSign() {
274         try {
275             Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
276             WSSecHeader secHeader = new WSSecHeader();
277             secHeader.insertSecurityHeader(doc);
278 
279             WSSecSecurityContextToken sctBuilder = new WSSecSecurityContextToken();
280             sctBuilder.prepare(doc, crypto);
281 
282             byte[] tempSecret = WSSecurityUtil.generateNonce(16);
283 
284             // Store the secret
285             callbackHandler.addSecretKey(sctBuilder.getIdentifier(), tempSecret);
286 
287             String tokenId = sctBuilder.getSctId();
288 
289             // Derived key encryption
290             WSSecDKEncrypt encrBuilder = new WSSecDKEncrypt();
291             encrBuilder.setSymmetricEncAlgorithm(WSConstants.AES_128);
292             encrBuilder.setExternalKey(tempSecret, tokenId);
293             encrBuilder.build(doc, secHeader);
294 
295             // Derived key signature
296             WSSecDKSign sigBuilder = new WSSecDKSign();
297             sigBuilder.setExternalKey(tempSecret, tokenId);
298             sigBuilder.setSignatureAlgorithm(WSConstants.HMAC_SHA1);
299             sigBuilder.build(doc, secHeader);
300 
301             sctBuilder.prependSCTElementToHeader(doc, secHeader);
302 
303             if (LOG.isDebugEnabled()) {
304                 String out = org.apache.ws.security.util.XMLUtils.PrettyDocumentToString(doc);
305                 LOG.debug(out);
306             }
307 
308             verify(doc);
309         } catch (Exception e) {
310             e.printStackTrace();
311             fail(e.getMessage());
312         }
313     }
314     
315     /**
316      * Test signature and verification using a SecurityContextToken directly,
317      * rather than using a DerivedKeyToken to point to a SecurityContextToken.
318      * See WSS-216 - https://issues.apache.org/jira/browse/WSS-216
319      */
320     @org.junit.Test
321     public void testSCTSign() {
322         try {
323             Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
324             WSSecHeader secHeader = new WSSecHeader();
325             secHeader.insertSecurityHeader(doc);
326 
327             WSSecSecurityContextToken sctBuilder = new WSSecSecurityContextToken();
328             sctBuilder.prepare(doc, crypto);
329 
330             byte[] tempSecret = WSSecurityUtil.generateNonce(16);
331 
332             // Store the secret
333             callbackHandler.addSecretKey(sctBuilder.getIdentifier(), tempSecret);
334 
335             String tokenId = sctBuilder.getSctId();
336 
337             WSSecSignature builder = new WSSecSignature();
338             builder.setSecretKey(tempSecret);
339             builder.setKeyIdentifierType(WSConstants.CUSTOM_SYMM_SIGNING);
340             builder.setCustomTokenValueType(WSConstants.WSC_SCT);
341             builder.setCustomTokenId(tokenId);
342             builder.setSignatureAlgorithm(SignatureMethod.HMAC_SHA1);
343             builder.build(doc, crypto, secHeader);
344             
345             sctBuilder.prependSCTElementToHeader(doc, secHeader);
346             
347             if (LOG.isDebugEnabled()) {
348                 LOG.debug("SCT sign");
349                 String outputString = 
350                     org.apache.ws.security.util.XMLUtils.PrettyDocumentToString(doc);
351                 LOG.debug(outputString);
352             }
353 
354             verify(doc);
355         } catch (Exception e) {
356             e.printStackTrace();
357             fail(e.getMessage());
358         }
359     }
360     
361     /**
362      * Verifies the soap envelope <p/>
363      * 
364      * @param envelope
365      * @throws Exception
366      *             Thrown when there is a problem in verification
367      */
368     private List<WSSecurityEngineResult> verify(Document doc) throws Exception {
369         List<WSSecurityEngineResult> results = 
370             secEngine.processSecurityHeader(doc, null, callbackHandler, crypto);
371         String outputString = 
372             org.apache.ws.security.util.XMLUtils.PrettyDocumentToString(doc);
373         assertTrue(outputString.indexOf("counter_port_type") > 0 ? true : false);
374         return results;
375     }
376 
377 
378 }