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 org.apache.ws.security.WSConstants;
23  import org.apache.ws.security.WSSConfig;
24  import org.apache.ws.security.WSSecurityEngineResult;
25  import org.apache.ws.security.WSSecurityException;
26  import org.apache.ws.security.WSSecurityEngine;
27  import org.apache.ws.security.common.CustomHandler;
28  import org.apache.ws.security.common.SOAPUtil;
29  import org.apache.ws.security.common.UsernamePasswordCallbackHandler;
30  import org.apache.ws.security.components.crypto.Crypto;
31  import org.apache.ws.security.components.crypto.CryptoFactory;
32  import org.apache.ws.security.handler.RequestData;
33  import org.apache.ws.security.handler.WSHandlerConstants;
34  import org.apache.ws.security.util.WSSecurityUtil;
35  import org.w3c.dom.Document;
36  
37  import javax.security.auth.callback.CallbackHandler;
38  
39  import java.util.List;
40  
41  /**
42   * WS-Security Test Case for UsernameToken Key Derivation, as defined in the 
43   * UsernameTokenProfile 1.1 specification. The derived keys are used for signature.
44   * Note that this functionality is different to the UTDerivedKeyTest test case,
45   * which uses the derived key in conjunction with wsc:DerivedKeyToken. It's also
46   * different to UTWseSignatureTest, which derives a key for signature using a 
47   * non-standard implementation.
48   */
49  public class UTSignatureTest extends org.junit.Assert {
50      private static final org.apache.commons.logging.Log LOG = 
51          org.apache.commons.logging.LogFactory.getLog(UTSignatureTest.class);
52      private WSSecurityEngine secEngine = new WSSecurityEngine();
53      private CallbackHandler callbackHandler = new UsernamePasswordCallbackHandler();
54      private Crypto crypto = null;
55      
56      public UTSignatureTest() throws Exception {
57          crypto = CryptoFactory.getInstance();
58      }
59  
60      /**
61       * Test using a UsernameToken derived key for signing a SOAP body
62       */
63      @org.junit.Test
64      public void testSignature() throws Exception {
65          Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
66          WSSecHeader secHeader = new WSSecHeader();
67          secHeader.insertSecurityHeader(doc);
68          
69          WSSecUsernameToken builder = new WSSecUsernameToken();
70          builder.setUserInfo("bob", "security");
71          builder.addDerivedKey(true, null, 1000);
72          builder.prepare(doc);
73          
74          WSSecSignature sign = new WSSecSignature();
75          sign.setCustomTokenValueType(WSConstants.USERNAMETOKEN_NS + "#UsernameToken");
76          sign.setCustomTokenId(builder.getId());
77          sign.setSecretKey(builder.getSecretKey());
78          sign.setKeyIdentifierType(WSConstants.CUSTOM_SYMM_SIGNING);
79          sign.setSignatureAlgorithm(WSConstants.HMAC_SHA1);
80          
81          Document signedDoc = sign.build(doc, null, secHeader);
82          builder.prependToHeader(secHeader);
83          
84          String outputString = 
85              org.apache.ws.security.util.XMLUtils.PrettyDocumentToString(signedDoc);
86          assertTrue(outputString.indexOf("wsse:Username") != -1);
87          assertTrue(outputString.indexOf("wsse:Password") == -1);
88          assertTrue(outputString.indexOf("wsse11:Salt") != -1);
89          assertTrue(outputString.indexOf("wsse11:Iteration") != -1);
90          if (LOG.isDebugEnabled()) {
91              LOG.debug(outputString);
92          }
93          
94          List<WSSecurityEngineResult> results = verify(signedDoc);
95          WSSecurityEngineResult actionResult =
96              WSSecurityUtil.fetchActionResult(results, WSConstants.UT_SIGN);
97          java.security.Principal principal = 
98              (java.security.Principal) actionResult.get(WSSecurityEngineResult.TAG_PRINCIPAL);
99          assertTrue(principal.getName().indexOf("bob") != -1);
100     }
101     
102     
103     /**
104      * Test using a UsernameToken derived key for signing a SOAP body. In this test the
105      * user is "colm" rather than "bob", and so signature verification should fail.
106      */
107     @org.junit.Test
108     public void testBadUserSignature() throws Exception {
109         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
110         WSSecHeader secHeader = new WSSecHeader();
111         secHeader.insertSecurityHeader(doc);
112         
113         WSSecUsernameToken builder = new WSSecUsernameToken();
114         builder.setUserInfo("colm", "security");
115         builder.addDerivedKey(true, null, 1000);
116         builder.prepare(doc);
117         
118         WSSecSignature sign = new WSSecSignature();
119         sign.setCustomTokenValueType(WSConstants.USERNAMETOKEN_NS + "#UsernameToken");
120         sign.setCustomTokenId(builder.getId());
121         sign.setSecretKey(builder.getSecretKey());
122         sign.setKeyIdentifierType(WSConstants.CUSTOM_SYMM_SIGNING);
123         sign.setSignatureAlgorithm(WSConstants.HMAC_SHA1);
124         
125         Document signedDoc = sign.build(doc, null, secHeader);
126         builder.prependToHeader(secHeader);
127         
128         String outputString = 
129             org.apache.ws.security.util.XMLUtils.PrettyDocumentToString(signedDoc);
130         if (LOG.isDebugEnabled()) {
131             LOG.debug(outputString);
132         }
133 
134         try {
135             verify(signedDoc);
136             fail("Failure expected on a bad derived signature");
137         } catch (WSSecurityException ex) {
138             assertTrue(ex.getErrorCode() == WSSecurityException.FAILED_AUTHENTICATION);
139             // expected
140         }
141     }
142     
143     /**
144      * Test using a UsernameToken derived key for signing a SOAP body via WSHandler
145      */
146     @org.junit.Test
147     public void testHandlerSignature() throws Exception {
148         
149         final WSSConfig cfg = WSSConfig.getNewInstance();
150         RequestData reqData = new RequestData();
151         reqData.setWssConfig(cfg);
152         java.util.Map<String, Object> messageContext = new java.util.TreeMap<String, Object>();
153         messageContext.put(WSHandlerConstants.PW_CALLBACK_REF, callbackHandler);
154         messageContext.put(WSHandlerConstants.USE_DERIVED_KEY, "true");
155         reqData.setMsgContext(messageContext);
156         reqData.setUsername("bob");
157         
158         final java.util.List<Integer> actions = new java.util.ArrayList<Integer>();
159         actions.add(Integer.valueOf(WSConstants.UT_SIGN));
160         
161         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
162         CustomHandler handler = new CustomHandler();
163         handler.send(
164             WSConstants.UT_SIGN, 
165             doc, 
166             reqData, 
167             actions,
168             true
169         );
170         
171         String outputString = 
172             org.apache.ws.security.util.XMLUtils.PrettyDocumentToString(doc);
173         assertTrue(outputString.indexOf("wsse:Username") != -1);
174         assertTrue(outputString.indexOf("wsse:Password") == -1);
175         assertTrue(outputString.indexOf("wsse11:Salt") != -1);
176         assertTrue(outputString.indexOf("wsse11:Iteration") != -1);
177         if (LOG.isDebugEnabled()) {
178             LOG.debug(outputString);
179         }
180         
181         List<WSSecurityEngineResult> results = verify(doc);
182         WSSecurityEngineResult actionResult =
183             WSSecurityUtil.fetchActionResult(results, WSConstants.UT_SIGN);
184         java.security.Principal principal = 
185             (java.security.Principal) actionResult.get(WSSecurityEngineResult.TAG_PRINCIPAL);
186         assertTrue(principal.getName().indexOf("bob") != -1);
187     }
188     
189     /**
190      * Test using a UsernameToken derived key for signing a SOAP body via WSHandler
191      */
192     @org.junit.Test
193     public void testHandlerSignatureIterations() throws Exception {
194         
195         final WSSConfig cfg = WSSConfig.getNewInstance();
196         RequestData reqData = new RequestData();
197         reqData.setWssConfig(cfg);
198         java.util.Map<String, Object> messageContext = new java.util.TreeMap<String, Object>();
199         messageContext.put(WSHandlerConstants.PW_CALLBACK_REF, callbackHandler);
200         messageContext.put(WSHandlerConstants.USE_DERIVED_KEY, "true");
201         messageContext.put(WSHandlerConstants.DERIVED_KEY_ITERATIONS, "1234");
202         reqData.setMsgContext(messageContext);
203         reqData.setUsername("bob");
204         
205         final java.util.List<Integer> actions = new java.util.ArrayList<Integer>();
206         actions.add(Integer.valueOf(WSConstants.UT_SIGN));
207         
208         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
209         CustomHandler handler = new CustomHandler();
210         handler.send(
211             WSConstants.UT_SIGN, 
212             doc, 
213             reqData, 
214             actions,
215             true
216         );
217         
218         String outputString = 
219             org.apache.ws.security.util.XMLUtils.PrettyDocumentToString(doc);
220         assertTrue(outputString.indexOf("wsse:Username") != -1);
221         assertTrue(outputString.indexOf("wsse:Password") == -1);
222         assertTrue(outputString.indexOf("wsse11:Salt") != -1);
223         assertTrue(outputString.indexOf("wsse11:Iteration") != -1);
224         assertTrue(outputString.indexOf("1234") != -1);
225         if (LOG.isDebugEnabled()) {
226             LOG.debug(outputString);
227         }
228         
229         List<WSSecurityEngineResult> results = verify(doc);
230         WSSecurityEngineResult actionResult =
231             WSSecurityUtil.fetchActionResult(results, WSConstants.UT_SIGN);
232         java.security.Principal principal = 
233             (java.security.Principal) actionResult.get(WSSecurityEngineResult.TAG_PRINCIPAL);
234         assertTrue(principal.getName().indexOf("bob") != -1);
235     }
236     
237     /**
238      * Verifies the soap envelope.
239      * 
240      * @param env soap envelope
241      * @throws java.lang.Exception Thrown when there is a problem in verification
242      */
243     private List<WSSecurityEngineResult> verify(Document doc) throws Exception {
244         return secEngine.processSecurityHeader(doc, null, callbackHandler, crypto);
245     }
246 
247 }