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.token;
21  
22  import org.apache.ws.security.WSSConfig;
23  import org.apache.ws.security.WSSecurityEngine;
24  import org.apache.ws.security.WSConstants;
25  import org.apache.ws.security.WSSecurityEngineResult;
26  import org.apache.ws.security.WSSecurityException;
27  import org.apache.ws.security.common.SOAPUtil;
28  import org.apache.ws.security.message.WSSecEncrypt;
29  import org.apache.ws.security.message.WSSecHeader;
30  import org.apache.ws.security.message.WSSecSignature;
31  import org.apache.ws.security.spnego.SpnegoTokenContext;
32  import org.apache.ws.security.util.Base64;
33  import org.apache.ws.security.util.WSSecurityUtil;
34  // import org.apache.ws.security.validate.KerberosTokenDecoderImpl;
35  import org.apache.ws.security.validate.KerberosTokenValidator;
36  import org.w3c.dom.Document;
37  
38  import java.security.Principal;
39  import java.util.List;
40  
41  import javax.crypto.SecretKey;
42  import javax.security.auth.kerberos.KerberosPrincipal;
43  import javax.xml.crypto.dsig.SignatureMethod;
44  
45  /**
46   * This is a test for a WSS4J client retrieving a service ticket from a KDC, and inserting
47   * it into the security header of a request, to be processed by WSS4J. The tests are @Ignored by
48   * default, as a KDC is needed. To replicate the test scenario, set up a KDC with user principal
49   * "alice" (keytab in "/etc/alice.keytab"), and host service "bob@service.ws.apache.org" 
50   * (keytab in "/etc/bob.keytab").
51   * The test can be run with:
52   * 
53   * mvn -Djava.security.auth.login.config=src/test/resources/kerberos.jaas test -Dtest=KerberosTest
54   * 
55   * To see the Kerberos stuff add "-Dsun.security.krb5.debug=true".
56   */
57  public class KerberosTest extends org.junit.Assert {
58      private static final org.apache.commons.logging.Log LOG = 
59          org.apache.commons.logging.LogFactory.getLog(KerberosTest.class);
60      
61      public KerberosTest() throws Exception {
62          WSSConfig.init();
63      }
64  
65      /**
66       * Test using the KerberosSecurity class to retrieve a service ticket from a KDC, wrap it
67       * in a BinarySecurityToken, and process it.
68       */
69      @org.junit.Test
70      @org.junit.Ignore
71      public void testKerberosCreationAndProcessing() throws Exception {
72          Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
73  
74          WSSecHeader secHeader = new WSSecHeader();
75          secHeader.insertSecurityHeader(doc);
76          
77          KerberosSecurity bst = new KerberosSecurity(doc);
78          bst.retrieveServiceTicket("alice", null, "bob@service.ws.apache.org");
79          WSSecurityUtil.prependChildElement(secHeader.getSecurityHeader(), bst.getElement());
80          
81          if (LOG.isDebugEnabled()) {
82              String outputString = 
83                  org.apache.ws.security.util.XMLUtils.PrettyDocumentToString(doc);
84              LOG.debug(outputString);
85          }
86          
87          // Configure the Validator
88          WSSConfig wssConfig = WSSConfig.getNewInstance();
89          KerberosTokenValidator validator = new KerberosTokenValidator();
90          validator.setContextName("bob");
91          validator.setServiceName("bob@service.ws.apache.org");
92          wssConfig.setValidator(WSSecurityEngine.BINARY_TOKEN, validator);
93          WSSecurityEngine secEngine = new WSSecurityEngine();
94          secEngine.setWssConfig(wssConfig);
95          
96          List<WSSecurityEngineResult> results = 
97              secEngine.processSecurityHeader(doc, null, null, null);
98          WSSecurityEngineResult actionResult =
99              WSSecurityUtil.fetchActionResult(results, WSConstants.BST);
100         BinarySecurity token =
101             (BinarySecurity)actionResult.get(WSSecurityEngineResult.TAG_BINARY_SECURITY_TOKEN);
102         assertTrue(token != null);
103         
104         Principal principal = (Principal)actionResult.get(WSSecurityEngineResult.TAG_PRINCIPAL);
105         assertTrue(principal instanceof KerberosPrincipal);
106         assertTrue(principal.getName().contains("alice"));
107     }
108     
109     /**
110      * Get and validate a SPNEGO token.
111      */
112     @org.junit.Test
113     @org.junit.Ignore
114     public void testSpnego() throws Exception {
115         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
116 
117         WSSecHeader secHeader = new WSSecHeader();
118         secHeader.insertSecurityHeader(doc);
119         
120         SpnegoTokenContext spnegoToken = new SpnegoTokenContext();
121         spnegoToken.retrieveServiceTicket("alice", null, "bob@service.ws.apache.org");
122         
123         byte[] token = spnegoToken.getToken();
124         assertNotNull(token);
125         
126         spnegoToken = new SpnegoTokenContext();
127         spnegoToken.validateServiceTicket("bob", null, "bob@service.ws.apache.org", token);
128         assertTrue(spnegoToken.isEstablished());
129     }
130     
131     /**
132      * Various unit tests for a kerberos client
133      */
134     @org.junit.Test
135     @org.junit.Ignore
136     public void testKerberosClient() throws Exception {
137         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
138         
139         try {
140             KerberosSecurity bst = new KerberosSecurity(doc);
141             bst.retrieveServiceTicket("alice2", null, "bob@service");
142             fail("Failure expected on an unknown user");
143         } catch (WSSecurityException ex) {
144             // expected
145         }
146         
147         
148         try {
149             KerberosSecurity bst = new KerberosSecurity(doc);
150             bst.retrieveServiceTicket("alice", null, "bob2@service");
151             fail("Failure expected on an unknown user");
152         } catch (WSSecurityException ex) {
153             // expected
154         }
155         
156     }
157     
158     /**
159      * Test using the KerberosSecurity class to retrieve a service ticket from a KDC, wrap it
160      * in a BinarySecurityToken, and use the session key to sign the SOAP Body.
161      */
162     @org.junit.Test
163     @org.junit.Ignore
164     public void testKerberosSignature() throws Exception {
165         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
166 
167         WSSecHeader secHeader = new WSSecHeader();
168         secHeader.insertSecurityHeader(doc);
169         
170         KerberosSecurity bst = new KerberosSecurity(doc);
171         bst.retrieveServiceTicket("alice", null, "bob@service.ws.apache.org");
172         bst.setID("Id-" + bst.hashCode());
173         WSSecurityUtil.prependChildElement(secHeader.getSecurityHeader(), bst.getElement());
174         
175         WSSecSignature sign = new WSSecSignature();
176         sign.setSignatureAlgorithm(SignatureMethod.HMAC_SHA1);
177         sign.setKeyIdentifierType(WSConstants.CUSTOM_SYMM_SIGNING);
178         sign.setCustomTokenId(bst.getID());
179         sign.setCustomTokenValueType(WSConstants.WSS_GSS_KRB_V5_AP_REQ);
180         
181         SecretKey secretKey = bst.getSecretKey();
182         sign.setSecretKey(secretKey.getEncoded());
183         
184         Document signedDoc = sign.build(doc, null, secHeader);
185         
186         if (LOG.isDebugEnabled()) {
187             String outputString = 
188                 org.apache.ws.security.util.XMLUtils.PrettyDocumentToString(signedDoc);
189             LOG.debug(outputString);
190         }
191         
192         // Configure the Validator
193         WSSConfig wssConfig = WSSConfig.getNewInstance();
194         KerberosTokenValidator validator = new KerberosTokenValidator();
195         validator.setContextName("bob");
196         validator.setServiceName("bob@service.ws.apache.org");
197         // validator.setKerberosTokenDecoder(new KerberosTokenDecoderImpl());
198         wssConfig.setValidator(WSSecurityEngine.BINARY_TOKEN, validator);
199         WSSecurityEngine secEngine = new WSSecurityEngine();
200         secEngine.setWssConfig(wssConfig);
201         
202         List<WSSecurityEngineResult> results = 
203             secEngine.processSecurityHeader(doc, null, null, null);
204         WSSecurityEngineResult actionResult =
205             WSSecurityUtil.fetchActionResult(results, WSConstants.BST);
206         BinarySecurity token =
207             (BinarySecurity)actionResult.get(WSSecurityEngineResult.TAG_BINARY_SECURITY_TOKEN);
208         assertTrue(token != null);
209         
210         Principal principal = (Principal)actionResult.get(WSSecurityEngineResult.TAG_PRINCIPAL);
211         assertTrue(principal instanceof KerberosPrincipal);
212         assertTrue(principal.getName().contains("alice"));
213     }
214     
215     
216     /**
217      * Test using the KerberosSecurity class to retrieve a service ticket from a KDC, wrap it
218      * in a BinarySecurityToken, and use the session key to sign the SOAP Body.
219      */
220     @org.junit.Test
221     @org.junit.Ignore
222     public void testKerberosSignatureKI() throws Exception {
223         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
224 
225         WSSecHeader secHeader = new WSSecHeader();
226         secHeader.insertSecurityHeader(doc);
227         
228         KerberosSecurity bst = new KerberosSecurity(doc);
229         bst.retrieveServiceTicket("alice", null, "bob@service.ws.apache.org");
230         bst.setID("Id-" + bst.hashCode());
231         
232         WSSecSignature sign = new WSSecSignature();
233         sign.setSignatureAlgorithm(SignatureMethod.HMAC_SHA1);
234         sign.setKeyIdentifierType(WSConstants.CUSTOM_KEY_IDENTIFIER);
235         sign.setCustomTokenValueType(WSConstants.WSS_KRB_KI_VALUE_TYPE);
236         
237         SecretKey secretKey = bst.getSecretKey();
238         byte[] keyData = secretKey.getEncoded();
239         sign.setSecretKey(keyData);
240         
241         byte[] digestBytes = WSSecurityUtil.generateDigest(bst.getToken());
242         sign.setCustomTokenId(Base64.encode(digestBytes));
243         
244         Document signedDoc = sign.build(doc, null, secHeader);
245         
246         WSSecurityUtil.prependChildElement(secHeader.getSecurityHeader(), bst.getElement());
247         
248         if (LOG.isDebugEnabled()) {
249             String outputString = 
250                 org.apache.ws.security.util.XMLUtils.PrettyDocumentToString(signedDoc);
251             LOG.debug(outputString);
252         }
253         
254         // Configure the Validator
255         WSSConfig wssConfig = WSSConfig.getNewInstance();
256         KerberosTokenValidator validator = new KerberosTokenValidator();
257         validator.setContextName("bob");
258         validator.setServiceName("bob@service.ws.apache.org");
259         // validator.setKerberosTokenDecoder(new KerberosTokenDecoderImpl());
260         wssConfig.setValidator(WSSecurityEngine.BINARY_TOKEN, validator);
261         WSSecurityEngine secEngine = new WSSecurityEngine();
262         secEngine.setWssConfig(wssConfig);
263         
264         List<WSSecurityEngineResult> results = 
265             secEngine.processSecurityHeader(doc, null, null, null);
266         WSSecurityEngineResult actionResult =
267             WSSecurityUtil.fetchActionResult(results, WSConstants.BST);
268         BinarySecurity token =
269             (BinarySecurity)actionResult.get(WSSecurityEngineResult.TAG_BINARY_SECURITY_TOKEN);
270         assertTrue(token != null);
271         
272         Principal principal = (Principal)actionResult.get(WSSecurityEngineResult.TAG_PRINCIPAL);
273         assertTrue(principal instanceof KerberosPrincipal);
274         assertTrue(principal.getName().contains("alice"));
275     }
276     
277     
278     /**
279      * Test using the KerberosSecurity class to retrieve a service ticket from a KDC, wrap it
280      * in a BinarySecurityToken, and use the session key to encrypt the SOAP Body.
281      */
282     @org.junit.Test
283     @org.junit.Ignore
284     public void testKerberosEncryption() throws Exception {
285         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
286 
287         WSSecHeader secHeader = new WSSecHeader();
288         secHeader.insertSecurityHeader(doc);
289         
290         KerberosSecurity bst = new KerberosSecurity(doc);
291         bst.retrieveServiceTicket("alice", null, "bob@service.ws.apache.org");
292         bst.setID("Id-" + bst.hashCode());
293         WSSecurityUtil.prependChildElement(secHeader.getSecurityHeader(), bst.getElement());
294         
295         WSSecEncrypt builder = new WSSecEncrypt();
296         builder.setSymmetricEncAlgorithm(WSConstants.AES_128);
297         SecretKey secretKey = bst.getSecretKey();
298         builder.setSymmetricKey(secretKey);
299         builder.setEncryptSymmKey(false);
300         builder.setCustomReferenceValue(WSConstants.WSS_GSS_KRB_V5_AP_REQ);
301         builder.setEncKeyId(bst.getID());
302 
303         Document encryptedDoc = builder.build(doc, null, secHeader);
304         
305         if (LOG.isDebugEnabled()) {
306             String outputString = 
307                 org.apache.ws.security.util.XMLUtils.PrettyDocumentToString(encryptedDoc);
308             LOG.debug(outputString);
309         }
310         
311         // Configure the Validator
312         WSSConfig wssConfig = WSSConfig.getNewInstance();
313         KerberosTokenValidator validator = new KerberosTokenValidator();
314         validator.setContextName("bob");
315         validator.setServiceName("bob@service.ws.apache.org");
316         // validator.setKerberosTokenDecoder(new KerberosTokenDecoderImpl());
317         wssConfig.setValidator(WSSecurityEngine.BINARY_TOKEN, validator);
318         WSSecurityEngine secEngine = new WSSecurityEngine();
319         secEngine.setWssConfig(wssConfig);
320         
321         List<WSSecurityEngineResult> results = 
322             secEngine.processSecurityHeader(encryptedDoc, null, null, null);
323         WSSecurityEngineResult actionResult =
324             WSSecurityUtil.fetchActionResult(results, WSConstants.BST);
325         BinarySecurity token =
326             (BinarySecurity)actionResult.get(WSSecurityEngineResult.TAG_BINARY_SECURITY_TOKEN);
327         assertTrue(token != null);
328         
329         Principal principal = (Principal)actionResult.get(WSSecurityEngineResult.TAG_PRINCIPAL);
330         assertTrue(principal instanceof KerberosPrincipal);
331         assertTrue(principal.getName().contains("alice"));
332     }
333     
334     /**
335      * Test using the KerberosSecurity class to retrieve a service ticket from a KDC, wrap it
336      * in a BinarySecurityToken, and use the session key to encrypt the SOAP Body.
337      */
338     @org.junit.Test
339     @org.junit.Ignore
340     public void testKerberosEncryptionBSTFirst() throws Exception {
341         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
342 
343         WSSecHeader secHeader = new WSSecHeader();
344         secHeader.insertSecurityHeader(doc);
345         
346         KerberosSecurity bst = new KerberosSecurity(doc);
347         bst.retrieveServiceTicket("alice", null, "bob@service.ws.apache.org");
348         bst.setID("Id-" + bst.hashCode());
349         
350         WSSecEncrypt builder = new WSSecEncrypt();
351         builder.setSymmetricEncAlgorithm(WSConstants.AES_128);
352         SecretKey secretKey = bst.getSecretKey();
353         builder.setSymmetricKey(secretKey);
354         builder.setEncryptSymmKey(false);
355         builder.setCustomReferenceValue(WSConstants.WSS_GSS_KRB_V5_AP_REQ);
356         builder.setEncKeyId(bst.getID());
357 
358         Document encryptedDoc = builder.build(doc, null, secHeader);
359         
360         WSSecurityUtil.prependChildElement(secHeader.getSecurityHeader(), bst.getElement());
361         
362         if (LOG.isDebugEnabled()) {
363             String outputString = 
364                 org.apache.ws.security.util.XMLUtils.PrettyDocumentToString(encryptedDoc);
365             LOG.debug(outputString);
366         }
367         
368         // Configure the Validator
369         WSSConfig wssConfig = WSSConfig.getNewInstance();
370         KerberosTokenValidator validator = new KerberosTokenValidator();
371         validator.setContextName("bob");
372         validator.setServiceName("bob@service.ws.apache.org");
373         // validator.setKerberosTokenDecoder(new KerberosTokenDecoderImpl());
374         wssConfig.setValidator(WSSecurityEngine.BINARY_TOKEN, validator);
375         WSSecurityEngine secEngine = new WSSecurityEngine();
376         secEngine.setWssConfig(wssConfig);
377         
378         List<WSSecurityEngineResult> results = 
379             secEngine.processSecurityHeader(encryptedDoc, null, null, null);
380         WSSecurityEngineResult actionResult =
381             WSSecurityUtil.fetchActionResult(results, WSConstants.BST);
382         BinarySecurity token =
383             (BinarySecurity)actionResult.get(WSSecurityEngineResult.TAG_BINARY_SECURITY_TOKEN);
384         assertTrue(token != null);
385         
386         Principal principal = (Principal)actionResult.get(WSSecurityEngineResult.TAG_PRINCIPAL);
387         assertTrue(principal instanceof KerberosPrincipal);
388         assertTrue(principal.getName().contains("alice"));
389     }
390     
391     /**
392      * Test using the KerberosSecurity class to retrieve a service ticket from a KDC, wrap it
393      * in a BinarySecurityToken, and use the session key to encrypt the SOAP Body.
394      */
395     @org.junit.Test
396     @org.junit.Ignore
397     public void testKerberosEncryptionKI() throws Exception {
398         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
399 
400         WSSecHeader secHeader = new WSSecHeader();
401         secHeader.insertSecurityHeader(doc);
402         
403         KerberosSecurity bst = new KerberosSecurity(doc);
404         bst.retrieveServiceTicket("alice", null, "bob@service.ws.apache.org");
405         bst.setID("Id-" + bst.hashCode());
406         
407         WSSecEncrypt builder = new WSSecEncrypt();
408         builder.setSymmetricEncAlgorithm(WSConstants.AES_128);
409         SecretKey secretKey = bst.getSecretKey();
410         builder.setSymmetricKey(secretKey);
411         builder.setEncryptSymmKey(false);
412         builder.setCustomReferenceValue(WSConstants.WSS_KRB_KI_VALUE_TYPE);
413 
414         byte[] digestBytes = WSSecurityUtil.generateDigest(bst.getToken());
415         builder.setEncKeyId(Base64.encode(digestBytes));
416         
417         Document encryptedDoc = builder.build(doc, null, secHeader);
418         
419         WSSecurityUtil.prependChildElement(secHeader.getSecurityHeader(), bst.getElement());
420         
421         if (LOG.isDebugEnabled()) {
422             String outputString = 
423                 org.apache.ws.security.util.XMLUtils.PrettyDocumentToString(encryptedDoc);
424             LOG.debug(outputString);
425         }
426         
427         // Configure the Validator
428         WSSConfig wssConfig = WSSConfig.getNewInstance();
429         KerberosTokenValidator validator = new KerberosTokenValidator();
430         validator.setContextName("bob");
431         validator.setServiceName("bob@service.ws.apache.org");
432         // validator.setKerberosTokenDecoder(new KerberosTokenDecoderImpl());
433         wssConfig.setValidator(WSSecurityEngine.BINARY_TOKEN, validator);
434         WSSecurityEngine secEngine = new WSSecurityEngine();
435         secEngine.setWssConfig(wssConfig);
436         
437         List<WSSecurityEngineResult> results = 
438             secEngine.processSecurityHeader(encryptedDoc, null, null, null);
439         WSSecurityEngineResult actionResult =
440             WSSecurityUtil.fetchActionResult(results, WSConstants.BST);
441         BinarySecurity token =
442             (BinarySecurity)actionResult.get(WSSecurityEngineResult.TAG_BINARY_SECURITY_TOKEN);
443         assertTrue(token != null);
444         
445         Principal principal = (Principal)actionResult.get(WSSecurityEngineResult.TAG_PRINCIPAL);
446         assertTrue(principal instanceof KerberosPrincipal);
447         assertTrue(principal.getName().contains("alice"));
448     
449     }
450     
451     
452 }