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