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  package org.apache.wss4j.integration.test.kerberos;
20  
21  import java.io.ByteArrayInputStream;
22  import java.io.ByteArrayOutputStream;
23  import java.io.File;
24  import java.io.IOException;
25  import java.nio.charset.StandardCharsets;
26  import java.security.Principal;
27  import java.util.ArrayList;
28  import java.util.List;
29  
30  import javax.crypto.SecretKey;
31  import javax.security.auth.callback.Callback;
32  import javax.security.auth.callback.CallbackHandler;
33  import javax.security.auth.callback.PasswordCallback;
34  import javax.security.auth.callback.UnsupportedCallbackException;
35  import javax.security.auth.kerberos.KerberosPrincipal;
36  import javax.xml.crypto.dsig.SignatureMethod;
37  import javax.xml.parsers.DocumentBuilderFactory;
38  import javax.xml.stream.XMLInputFactory;
39  import javax.xml.stream.XMLStreamReader;
40  import javax.xml.stream.XMLStreamWriter;
41  import javax.xml.transform.TransformerFactory;
42  import javax.xml.transform.dom.DOMSource;
43  import javax.xml.transform.stream.StreamResult;
44  
45  import org.apache.kerby.kerberos.kerb.server.SimpleKdcServer;
46  import org.apache.wss4j.common.ext.WSSecurityException;
47  import org.apache.wss4j.common.kerberos.KerberosContextAndServiceNameCallback;
48  import org.apache.wss4j.common.spnego.SpnegoTokenContext;
49  import org.apache.wss4j.common.token.BinarySecurity;
50  import org.apache.wss4j.common.util.KeyUtils;
51  import org.apache.wss4j.common.util.SOAPUtil;
52  import org.apache.wss4j.common.util.XMLUtils;
53  import org.apache.wss4j.dom.WSConstants;
54  
55  import org.apache.wss4j.dom.engine.WSSConfig;
56  import org.apache.wss4j.dom.engine.WSSecurityEngine;
57  import org.apache.wss4j.dom.engine.WSSecurityEngineResult;
58  import org.apache.wss4j.dom.handler.WSHandlerResult;
59  import org.apache.wss4j.dom.message.WSSecEncrypt;
60  import org.apache.wss4j.dom.message.WSSecHeader;
61  import org.apache.wss4j.dom.message.WSSecSignature;
62  import org.apache.wss4j.dom.message.token.KerberosSecurity;
63  import org.apache.wss4j.dom.util.WSSecurityUtil;
64  import org.apache.wss4j.dom.validate.KerberosTokenValidator;
65  import org.apache.wss4j.stax.ext.WSSConstants;
66  import org.apache.wss4j.stax.ext.WSSSecurityProperties;
67  import org.apache.wss4j.stax.securityEvent.KerberosTokenSecurityEvent;
68  import org.apache.wss4j.stax.setup.InboundWSSec;
69  import org.apache.wss4j.stax.setup.OutboundWSSec;
70  import org.apache.wss4j.stax.setup.WSSec;
71  import org.apache.wss4j.stax.test.utils.StAX2DOM;
72  import org.apache.wss4j.stax.test.utils.XmlReaderToWriter;
73  import org.apache.xml.security.exceptions.XMLSecurityException;
74  import org.apache.xml.security.stax.securityEvent.SecurityEvent;
75  import org.apache.xml.security.stax.securityEvent.SecurityEventListener;
76  
77  import org.junit.jupiter.api.AfterAll;
78  import org.junit.jupiter.api.BeforeAll;
79  import org.junit.jupiter.api.Test;
80  import org.w3c.dom.Document;
81  import org.w3c.dom.NodeList;
82  
83  import static org.junit.jupiter.api.Assertions.assertEquals;
84  import static org.junit.jupiter.api.Assertions.assertNotNull;
85  import static org.junit.jupiter.api.Assertions.assertTrue;
86  import static org.junit.jupiter.api.Assertions.fail;
87  
88  public class KerberosTest {
89  
90      private static final org.slf4j.Logger LOG =
91          org.slf4j.LoggerFactory.getLogger(KerberosTest.class);
92  
93      private static final XMLInputFactory xmlInputFactory = XMLInputFactory.newInstance();
94      private static final TransformerFactory TRANSFORMER_FACTORY = TransformerFactory.newInstance();
95      private static DocumentBuilderFactory dbf;
96  
97      private static boolean runTests = true;
98  
99      private static SimpleKdcServer kerbyServer;
100 
101     @BeforeAll
102     public static void setUp() throws Exception {
103 
104         WSSConfig.init();
105 
106         String basedir = System.getProperty("basedir");
107         if (basedir == null) {
108             basedir = new File(".").getCanonicalPath();
109         }
110 
111         // System.setProperty("sun.security.krb5.debug", "true");
112         System.setProperty("java.security.auth.login.config", basedir + "/target/test-classes/kerberos/kerberos.jaas");
113         System.setProperty("java.security.krb5.conf", basedir + "/target/krb5.conf");
114 
115         kerbyServer = new SimpleKdcServer();
116 
117         kerbyServer.setKdcRealm("service.ws.apache.org");
118         kerbyServer.setAllowUdp(false);
119         kerbyServer.setWorkDir(new File(basedir + "/target"));
120 
121         //kerbyServer.setInnerKdcImpl(new NettyKdcServerImpl(kerbyServer.getKdcSetting()));
122 
123         kerbyServer.init();
124 
125         // Create principals
126         String alice = "alice@service.ws.apache.org";
127         String bob = "bob/service.ws.apache.org@service.ws.apache.org";
128 
129         kerbyServer.createPrincipal(alice, "alice");
130         kerbyServer.createPrincipal(bob, "bob");
131 
132         kerbyServer.start();
133 
134         if ("IBM Corporation".equals(System.getProperty("java.vendor"))) {
135             runTests = false;
136         }
137 
138         dbf = DocumentBuilderFactory.newInstance();
139         dbf.setNamespaceAware(true);
140         dbf.setIgnoringComments(false);
141         dbf.setCoalescing(false);
142         dbf.setIgnoringElementContentWhitespace(false);
143 
144         xmlInputFactory.setProperty(XMLInputFactory.IS_COALESCING, false);
145         xmlInputFactory.setProperty(XMLInputFactory.SUPPORT_DTD, false);
146     }
147 
148     @AfterAll
149     public static void tearDown() throws Exception {
150         if (kerbyServer != null) {
151             kerbyServer.stop();
152         }
153     }
154 
155     //
156     // DOM tests
157     //
158 
159     /**
160      * Test using the KerberosSecurity class to retrieve a service ticket from a KDC, wrap it
161      * in a BinarySecurityToken, and process it.
162      */
163     @Test
164     public void testKerberosCreationAndProcessing() throws Exception {
165         if (!runTests) {
166             System.out.println("Skipping test because kerberos server could not be started");
167             return;
168         }
169 
170         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
171 
172         WSSecHeader secHeader = new WSSecHeader(doc);
173         secHeader.insertSecurityHeader();
174 
175         KerberosSecurity bst = new KerberosSecurity(doc);
176         CallbackHandler callbackHandler = new CallbackHandler() {
177             @Override
178             public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
179                 PasswordCallback passwordCallback = (PasswordCallback)callbacks[0];
180                 if (passwordCallback.getPrompt().contains("alice")) {
181                     passwordCallback.setPassword("alice".toCharArray());
182                 } else if (passwordCallback.getPrompt().contains("bob")) {
183                     passwordCallback.setPassword("bob".toCharArray());
184                 }
185             }
186         };
187         bst.retrieveServiceTicket("alice", callbackHandler, "bob@service.ws.apache.org");
188         WSSecurityUtil.prependChildElement(secHeader.getSecurityHeaderElement(), bst.getElement());
189 
190         if (LOG.isDebugEnabled()) {
191             String outputString =
192                 XMLUtils.prettyDocumentToString(doc);
193             LOG.debug(outputString);
194         }
195 
196         // Configure the Validator
197         WSSConfig wssConfig = WSSConfig.getNewInstance();
198         KerberosTokenValidator validator = new KerberosTokenValidator();
199         validator.setContextName("bob");
200         validator.setServiceName("bob@service.ws.apache.org");
201         wssConfig.setValidator(WSConstants.BINARY_TOKEN, validator);
202         WSSecurityEngine secEngine = new WSSecurityEngine();
203         secEngine.setWssConfig(wssConfig);
204 
205         WSHandlerResult results =
206             secEngine.processSecurityHeader(doc, null, callbackHandler, null);
207         WSSecurityEngineResult actionResult =
208             results.getActionResults().get(WSConstants.BST).get(0);
209         BinarySecurity token =
210             (BinarySecurity)actionResult.get(WSSecurityEngineResult.TAG_BINARY_SECURITY_TOKEN);
211         assertNotNull(token);
212 
213         Principal principal = (Principal)actionResult.get(WSSecurityEngineResult.TAG_PRINCIPAL);
214         assertTrue(principal instanceof KerberosPrincipal);
215         assertTrue(principal.getName().contains("alice"));
216     }
217 
218     /**
219      * Get and validate a SPNEGO token.
220      */
221     @Test
222     public void testSpnego() throws Exception {
223         if (!runTests) {
224             System.out.println("Skipping test because kerberos server could not be started");
225             return;
226         }
227 
228         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
229 
230         WSSecHeader secHeader = new WSSecHeader(doc);
231         secHeader.insertSecurityHeader();
232 
233         SpnegoTokenContext spnegoToken = new SpnegoTokenContext();
234         CallbackHandler callbackHandler = new CallbackHandler() {
235             @Override
236             public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
237                 PasswordCallback passwordCallback = (PasswordCallback)callbacks[0];
238                 if (passwordCallback.getPrompt().contains("alice")) {
239                     passwordCallback.setPassword("alice".toCharArray());
240                 } else if (passwordCallback.getPrompt().contains("bob")) {
241                     passwordCallback.setPassword("bob".toCharArray());
242                 }
243             }
244         };
245         spnegoToken.retrieveServiceTicket("alice", callbackHandler, "bob@service.ws.apache.org");
246 
247         byte[] token = spnegoToken.getToken();
248         assertNotNull(token);
249 
250         spnegoToken = new SpnegoTokenContext();
251         spnegoToken.validateServiceTicket("bob", callbackHandler, "bob@service.ws.apache.org", token);
252         assertTrue(spnegoToken.isEstablished());
253     }
254 
255     /**
256      * Various unit tests for a kerberos client
257      */
258     @Test
259     public void testKerberosClient() throws Exception {
260         if (!runTests) {
261             System.out.println("Skipping test because kerberos server could not be started");
262             return;
263         }
264 
265         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
266 
267         CallbackHandler callbackHandler = new CallbackHandler() {
268             @Override
269             public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
270                 PasswordCallback passwordCallback = (PasswordCallback)callbacks[0];
271                 if (passwordCallback.getPrompt().contains("alice")) {
272                     passwordCallback.setPassword("alice".toCharArray());
273                 } else if (passwordCallback.getPrompt().contains("bob")) {
274                     passwordCallback.setPassword("bob".toCharArray());
275                 }
276             }
277         };
278 
279         try {
280             KerberosSecurity bst = new KerberosSecurity(doc);
281             bst.retrieveServiceTicket("alice2", callbackHandler, "bob@service");
282             fail("Failure expected on an unknown user");
283         } catch (WSSecurityException ex) {
284             assertTrue(ex.getMessage().startsWith("An error occurred in trying to obtain a TGT:"));
285         }
286 
287 
288         try {
289             KerberosSecurity bst = new KerberosSecurity(doc);
290             bst.retrieveServiceTicket("alice", callbackHandler, "bob2@service");
291             fail("Failure expected on an unknown user");
292         } catch (WSSecurityException ex) {
293             assertEquals(ex.getMessage(), "An error occurred in trying to obtain a service ticket");
294         }
295 
296     }
297 
298     /**
299      * Test using the KerberosSecurity class to retrieve a service ticket from a KDC, wrap it
300      * in a BinarySecurityToken, and use the session key to sign the SOAP Body.
301      */
302     @Test
303     public void testKerberosSignature() throws Exception {
304         if (!runTests) {
305             System.out.println("Skipping test because kerberos server could not be started");
306             return;
307         }
308 
309         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
310 
311         WSSecHeader secHeader = new WSSecHeader(doc);
312         secHeader.insertSecurityHeader();
313 
314         KerberosSecurity bst = new KerberosSecurity(doc);
315         CallbackHandler callbackHandler = new CallbackHandler() {
316             @Override
317             public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
318                 if (callbacks[0] instanceof PasswordCallback) {
319                     PasswordCallback passwordCallback = (PasswordCallback)callbacks[0];
320                     if (passwordCallback.getPrompt().contains("alice")) {
321                         passwordCallback.setPassword("alice".toCharArray());
322                     } else if (passwordCallback.getPrompt().contains("bob")) {
323                         passwordCallback.setPassword("bob".toCharArray());
324                     }
325                 }
326             }
327         };
328         bst.retrieveServiceTicket("alice", callbackHandler, "bob@service.ws.apache.org");
329         bst.setID("Id-" + bst.hashCode());
330         WSSecurityUtil.prependChildElement(secHeader.getSecurityHeaderElement(), bst.getElement());
331 
332         WSSecSignature sign = new WSSecSignature(secHeader);
333         sign.setSignatureAlgorithm(SignatureMethod.HMAC_SHA1);
334         sign.setKeyIdentifierType(WSConstants.CUSTOM_SYMM_SIGNING);
335         sign.setCustomTokenId(bst.getID());
336         sign.setCustomTokenValueType(WSConstants.WSS_GSS_KRB_V5_AP_REQ);
337 
338         SecretKey secretKey = bst.getSecretKey();
339         sign.setSecretKey(secretKey.getEncoded());
340 
341         Document signedDoc = sign.build(null);
342 
343         if (LOG.isDebugEnabled()) {
344             String outputString =
345                 XMLUtils.prettyDocumentToString(signedDoc);
346             LOG.debug(outputString);
347         }
348 
349         // Configure the Validator
350         WSSConfig wssConfig = WSSConfig.getNewInstance();
351         KerberosTokenValidator validator = new KerberosTokenValidator();
352         validator.setContextName("bob");
353         validator.setServiceName("bob@service.ws.apache.org");
354         wssConfig.setValidator(WSConstants.BINARY_TOKEN, validator);
355         WSSecurityEngine secEngine = new WSSecurityEngine();
356         secEngine.setWssConfig(wssConfig);
357 
358         WSHandlerResult results =
359             secEngine.processSecurityHeader(doc, null, callbackHandler, null);
360         WSSecurityEngineResult actionResult =
361             results.getActionResults().get(WSConstants.BST).get(0);
362         BinarySecurity token =
363             (BinarySecurity)actionResult.get(WSSecurityEngineResult.TAG_BINARY_SECURITY_TOKEN);
364         assertNotNull(token);
365 
366         Principal principal = (Principal)actionResult.get(WSSecurityEngineResult.TAG_PRINCIPAL);
367         assertTrue(principal instanceof KerberosPrincipal);
368         assertTrue(principal.getName().contains("alice"));
369     }
370 
371 
372     /**
373      * Test using the KerberosSecurity class to retrieve a service ticket from a KDC, wrap it
374      * in a BinarySecurityToken, and use the session key to sign the SOAP Body.
375      */
376     @Test
377     public void testKerberosSignatureKI() throws Exception {
378         if (!runTests) {
379             System.out.println("Skipping test because kerberos server could not be started");
380             return;
381         }
382 
383         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
384 
385         WSSecHeader secHeader = new WSSecHeader(doc);
386         secHeader.insertSecurityHeader();
387 
388         KerberosSecurity bst = new KerberosSecurity(doc);
389         CallbackHandler callbackHandler = new CallbackHandler() {
390             @Override
391             public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
392                 if (callbacks[0] instanceof PasswordCallback) {
393                     PasswordCallback passwordCallback = (PasswordCallback)callbacks[0];
394                     if (passwordCallback.getPrompt().contains("alice")) {
395                         passwordCallback.setPassword("alice".toCharArray());
396                     } else if (passwordCallback.getPrompt().contains("bob")) {
397                         passwordCallback.setPassword("bob".toCharArray());
398                     }
399                 }
400             }
401         };
402         bst.retrieveServiceTicket("alice", callbackHandler, "bob@service.ws.apache.org");
403         bst.setID("Id-" + bst.hashCode());
404 
405         WSSecSignature sign = new WSSecSignature(secHeader);
406         sign.setSignatureAlgorithm(SignatureMethod.HMAC_SHA1);
407         sign.setKeyIdentifierType(WSConstants.CUSTOM_KEY_IDENTIFIER);
408         sign.setCustomTokenValueType(WSConstants.WSS_KRB_KI_VALUE_TYPE);
409 
410         SecretKey secretKey = bst.getSecretKey();
411         byte[] keyData = secretKey.getEncoded();
412         sign.setSecretKey(keyData);
413 
414         byte[] digestBytes = KeyUtils.generateDigest(bst.getToken());
415         sign.setCustomTokenId(org.apache.xml.security.utils.XMLUtils.encodeToString(digestBytes));
416 
417         Document signedDoc = sign.build(null);
418 
419         WSSecurityUtil.prependChildElement(secHeader.getSecurityHeaderElement(), bst.getElement());
420 
421         if (LOG.isDebugEnabled()) {
422             String outputString =
423                 XMLUtils.prettyDocumentToString(signedDoc);
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         wssConfig.setValidator(WSConstants.BINARY_TOKEN, validator);
433         WSSecurityEngine secEngine = new WSSecurityEngine();
434         secEngine.setWssConfig(wssConfig);
435 
436         WSHandlerResult results =
437             secEngine.processSecurityHeader(doc, null, callbackHandler, null);
438         WSSecurityEngineResult actionResult =
439             results.getActionResults().get(WSConstants.BST).get(0);
440         BinarySecurity token =
441             (BinarySecurity)actionResult.get(WSSecurityEngineResult.TAG_BINARY_SECURITY_TOKEN);
442         assertNotNull(token);
443 
444         Principal principal = (Principal)actionResult.get(WSSecurityEngineResult.TAG_PRINCIPAL);
445         assertTrue(principal instanceof KerberosPrincipal);
446         assertTrue(principal.getName().contains("alice"));
447     }
448 
449     /**
450      * Test using the KerberosSecurity class to retrieve a service ticket from a KDC, wrap it
451      * in a BinarySecurityToken, and use the session key to encrypt the SOAP Body.
452      */
453     @Test
454     public void testKerberosEncryption() throws Exception {
455         if (!runTests) {
456             System.out.println("Skipping test because kerberos server could not be started");
457             return;
458         }
459 
460         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
461 
462         WSSecHeader secHeader = new WSSecHeader(doc);
463         secHeader.insertSecurityHeader();
464 
465         KerberosSecurity bst = new KerberosSecurity(doc);
466         CallbackHandler callbackHandler = new CallbackHandler() {
467             @Override
468             public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
469                 if (callbacks[0] instanceof PasswordCallback) {
470                     PasswordCallback passwordCallback = (PasswordCallback)callbacks[0];
471                     if (passwordCallback.getPrompt().contains("alice")) {
472                         passwordCallback.setPassword("alice".toCharArray());
473                     } else if (passwordCallback.getPrompt().contains("bob")) {
474                         passwordCallback.setPassword("bob".toCharArray());
475                     }
476                 }
477             }
478         };
479         bst.retrieveServiceTicket("alice", callbackHandler, "bob@service.ws.apache.org");
480         bst.setID("Id-" + bst.hashCode());
481         WSSecurityUtil.prependChildElement(secHeader.getSecurityHeaderElement(), bst.getElement());
482 
483         WSSecEncrypt builder = new WSSecEncrypt(secHeader);
484         builder.setSymmetricEncAlgorithm(WSConstants.AES_128);
485         SecretKey secretKey = bst.getSecretKey();
486         builder.setEncryptSymmKey(false);
487         builder.setCustomReferenceValue(WSConstants.WSS_GSS_KRB_V5_AP_REQ);
488         builder.setEncKeyId(bst.getID());
489 
490         Document encryptedDoc = builder.build(null, secretKey);
491 
492         if (LOG.isDebugEnabled()) {
493             String outputString =
494                 XMLUtils.prettyDocumentToString(encryptedDoc);
495             LOG.debug(outputString);
496         }
497 
498         // Configure the Validator
499         WSSConfig wssConfig = WSSConfig.getNewInstance();
500         KerberosTokenValidator validator = new KerberosTokenValidator();
501         validator.setContextName("bob");
502         validator.setServiceName("bob@service.ws.apache.org");
503         wssConfig.setValidator(WSConstants.BINARY_TOKEN, validator);
504         WSSecurityEngine secEngine = new WSSecurityEngine();
505         secEngine.setWssConfig(wssConfig);
506 
507         WSHandlerResult results =
508             secEngine.processSecurityHeader(encryptedDoc, null, callbackHandler, null);
509         WSSecurityEngineResult actionResult =
510             results.getActionResults().get(WSConstants.BST).get(0);
511         BinarySecurity token =
512             (BinarySecurity)actionResult.get(WSSecurityEngineResult.TAG_BINARY_SECURITY_TOKEN);
513         assertNotNull(token);
514 
515         Principal principal = (Principal)actionResult.get(WSSecurityEngineResult.TAG_PRINCIPAL);
516         assertTrue(principal instanceof KerberosPrincipal);
517         assertTrue(principal.getName().contains("alice"));
518     }
519 
520     /**
521      * Test using the KerberosSecurity class to retrieve a service ticket from a KDC, wrap it
522      * in a BinarySecurityToken, and use the session key to encrypt the SOAP Body.
523      */
524     @Test
525     public void testKerberosEncryptionBSTFirst() throws Exception {
526         if (!runTests) {
527             System.out.println("Skipping test because kerberos server could not be started");
528             return;
529         }
530 
531         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
532 
533         WSSecHeader secHeader = new WSSecHeader(doc);
534         secHeader.insertSecurityHeader();
535 
536         KerberosSecurity bst = new KerberosSecurity(doc);
537         CallbackHandler callbackHandler = new CallbackHandler() {
538             @Override
539             public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
540                 if (callbacks[0] instanceof PasswordCallback) {
541                     PasswordCallback passwordCallback = (PasswordCallback)callbacks[0];
542                     if (passwordCallback.getPrompt().contains("alice")) {
543                         passwordCallback.setPassword("alice".toCharArray());
544                     } else if (passwordCallback.getPrompt().contains("bob")) {
545                         passwordCallback.setPassword("bob".toCharArray());
546                     }
547                 }
548             }
549         };
550         bst.retrieveServiceTicket("alice", callbackHandler, "bob@service.ws.apache.org");
551         bst.setID("Id-" + bst.hashCode());
552 
553         WSSecEncrypt builder = new WSSecEncrypt(secHeader);
554         builder.setSymmetricEncAlgorithm(WSConstants.AES_128);
555         SecretKey secretKey = bst.getSecretKey();
556         builder.setEncryptSymmKey(false);
557         builder.setCustomReferenceValue(WSConstants.WSS_GSS_KRB_V5_AP_REQ);
558         builder.setEncKeyId(bst.getID());
559 
560         Document encryptedDoc = builder.build(null, secretKey);
561 
562         WSSecurityUtil.prependChildElement(secHeader.getSecurityHeaderElement(), bst.getElement());
563 
564         if (LOG.isDebugEnabled()) {
565             String outputString =
566                 XMLUtils.prettyDocumentToString(encryptedDoc);
567             LOG.debug(outputString);
568         }
569 
570         // Configure the Validator
571         WSSConfig wssConfig = WSSConfig.getNewInstance();
572         KerberosTokenValidator validator = new KerberosTokenValidator();
573         validator.setContextName("bob");
574         validator.setServiceName("bob@service.ws.apache.org");
575         wssConfig.setValidator(WSConstants.BINARY_TOKEN, validator);
576         WSSecurityEngine secEngine = new WSSecurityEngine();
577         secEngine.setWssConfig(wssConfig);
578 
579         WSHandlerResult results =
580             secEngine.processSecurityHeader(encryptedDoc, null, callbackHandler, null);
581         WSSecurityEngineResult actionResult =
582             results.getActionResults().get(WSConstants.BST).get(0);
583         BinarySecurity token =
584             (BinarySecurity)actionResult.get(WSSecurityEngineResult.TAG_BINARY_SECURITY_TOKEN);
585         assertNotNull(token);
586 
587         Principal principal = (Principal)actionResult.get(WSSecurityEngineResult.TAG_PRINCIPAL);
588         assertTrue(principal instanceof KerberosPrincipal);
589         assertTrue(principal.getName().contains("alice"));
590     }
591 
592     /**
593      * Test using the KerberosSecurity class to retrieve a service ticket from a KDC, wrap it
594      * in a BinarySecurityToken, and use the session key to encrypt the SOAP Body.
595      */
596     @Test
597     public void testKerberosEncryptionKI() throws Exception {
598         if (!runTests) {
599             System.out.println("Skipping test because kerberos server could not be started");
600             return;
601         }
602 
603         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
604 
605         WSSecHeader secHeader = new WSSecHeader(doc);
606         secHeader.insertSecurityHeader();
607 
608         KerberosSecurity bst = new KerberosSecurity(doc);
609         CallbackHandler callbackHandler = new CallbackHandler() {
610             @Override
611             public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
612                 if (callbacks[0] instanceof PasswordCallback) {
613                     PasswordCallback passwordCallback = (PasswordCallback)callbacks[0];
614                     if (passwordCallback.getPrompt().contains("alice")) {
615                         passwordCallback.setPassword("alice".toCharArray());
616                     } else if (passwordCallback.getPrompt().contains("bob")) {
617                         passwordCallback.setPassword("bob".toCharArray());
618                     }
619                 }
620             }
621         };
622         bst.retrieveServiceTicket("alice", callbackHandler, "bob@service.ws.apache.org");
623         bst.setID("Id-" + bst.hashCode());
624 
625         WSSecEncrypt builder = new WSSecEncrypt(secHeader);
626         builder.setSymmetricEncAlgorithm(WSConstants.AES_128);
627         SecretKey secretKey = bst.getSecretKey();
628         builder.setEncryptSymmKey(false);
629         builder.setCustomReferenceValue(WSConstants.WSS_KRB_KI_VALUE_TYPE);
630 
631         byte[] digestBytes = KeyUtils.generateDigest(bst.getToken());
632         builder.setEncKeyId(org.apache.xml.security.utils.XMLUtils.encodeToString(digestBytes));
633 
634         Document encryptedDoc = builder.build(null, secretKey);
635 
636         WSSecurityUtil.prependChildElement(secHeader.getSecurityHeaderElement(), bst.getElement());
637 
638         if (LOG.isDebugEnabled()) {
639             String outputString =
640                 XMLUtils.prettyDocumentToString(encryptedDoc);
641             LOG.debug(outputString);
642         }
643 
644         // Configure the Validator
645         WSSConfig wssConfig = WSSConfig.getNewInstance();
646         KerberosTokenValidator validator = new KerberosTokenValidator();
647         validator.setContextName("bob");
648         validator.setServiceName("bob@service.ws.apache.org");
649         wssConfig.setValidator(WSConstants.BINARY_TOKEN, validator);
650         WSSecurityEngine secEngine = new WSSecurityEngine();
651         secEngine.setWssConfig(wssConfig);
652 
653         WSHandlerResult results =
654             secEngine.processSecurityHeader(encryptedDoc, null, callbackHandler, null);
655         WSSecurityEngineResult actionResult =
656             results.getActionResults().get(WSConstants.BST).get(0);
657         BinarySecurity token =
658             (BinarySecurity)actionResult.get(WSSecurityEngineResult.TAG_BINARY_SECURITY_TOKEN);
659         assertNotNull(token);
660 
661         Principal principal = (Principal)actionResult.get(WSSecurityEngineResult.TAG_PRINCIPAL);
662         assertTrue(principal instanceof KerberosPrincipal);
663         assertTrue(principal.getName().contains("alice"));
664     }
665 
666     //
667     // Streaming tests
668     //
669     @Test
670     public void testKerberosSignatureOutbound() throws Exception {
671         if (!runTests) {
672             System.out.println("Skipping test because kerberos server could not be started");
673             return;
674         }
675 
676         Document document;
677         {
678             WSSSecurityProperties securityProperties = new WSSSecurityProperties();
679             List<WSSConstants.Action> actions = new ArrayList<>();
680             actions.add(WSSConstants.SIGNATURE_WITH_KERBEROS_TOKEN);
681             securityProperties.setActions(actions);
682             securityProperties.setCallbackHandler(new CallbackHandler() {
683                 @Override
684                 public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
685                     if (callbacks[0] instanceof KerberosContextAndServiceNameCallback) {
686                         KerberosContextAndServiceNameCallback kerberosContextAndServiceNameCallback =
687                                 (KerberosContextAndServiceNameCallback) callbacks[0];
688                         kerberosContextAndServiceNameCallback.setContextName("alice");
689                         kerberosContextAndServiceNameCallback.setServiceName("bob@service.ws.apache.org");
690                     } else if (callbacks[0] instanceof PasswordCallback) {
691                         PasswordCallback passwordCallback = (PasswordCallback) callbacks[0];
692                         if (passwordCallback.getPrompt().contains("alice")) {
693                             passwordCallback.setPassword("alice".toCharArray());
694                         }
695                     }
696                 }
697             });
698 
699             ByteArrayOutputStream baos = new ByteArrayOutputStream();
700 
701             OutboundWSSec wsSecOut = WSSec.getOutboundWSSec(securityProperties);
702             XMLStreamWriter xmlStreamWriter = wsSecOut.processOutMessage(baos, StandardCharsets.UTF_8.name(), new ArrayList<>());
703             XMLStreamReader xmlStreamReader = xmlInputFactory.createXMLStreamReader(this.getClass().getClassLoader().getResourceAsStream("testdata/plain-soap-1.1.xml"));
704             XmlReaderToWriter.writeAll(xmlStreamReader, xmlStreamWriter);
705             xmlStreamWriter.close();
706 
707             document = dbf.newDocumentBuilder().parse(new ByteArrayInputStream(baos.toByteArray()));
708             NodeList nodeList = document.getElementsByTagNameNS(WSSConstants.TAG_dsig_Signature.getNamespaceURI(), WSSConstants.TAG_dsig_Signature.getLocalPart());
709             assertEquals(nodeList.getLength(), 1);
710         }
711 
712         //done signature; now test sig-verification:
713         {
714             // Configure the Validator
715             WSSConfig wssConfig = WSSConfig.getNewInstance();
716             KerberosTokenValidator validator = new KerberosTokenValidator();
717             validator.setContextName("bob");
718             validator.setServiceName("bob@service.ws.apache.org");
719             wssConfig.setValidator(WSConstants.BINARY_TOKEN, validator);
720             WSSecurityEngine secEngine = new WSSecurityEngine();
721             secEngine.setWssConfig(wssConfig);
722 
723             CallbackHandler callbackHandler = new CallbackHandler() {
724                 @Override
725                 public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
726                     if (callbacks[0] instanceof PasswordCallback) {
727                         PasswordCallback passwordCallback = (PasswordCallback) callbacks[0];
728                         if (passwordCallback.getPrompt().contains("bob")) {
729                             passwordCallback.setPassword("bob".toCharArray());
730                         }
731                     }
732                 }
733             };
734 
735             WSHandlerResult results =
736                     secEngine.processSecurityHeader(document, null, callbackHandler, null);
737             WSSecurityEngineResult actionResult =
738                     results.getActionResults().get(WSConstants.BST).get(0);
739             BinarySecurity token =
740                     (BinarySecurity) actionResult.get(WSSecurityEngineResult.TAG_BINARY_SECURITY_TOKEN);
741             assertNotNull(token);
742 
743             Principal principal = (Principal) actionResult.get(WSSecurityEngineResult.TAG_PRINCIPAL);
744             assertTrue(principal instanceof KerberosPrincipal);
745             assertTrue(principal.getName().contains("alice"));
746         }
747     }
748 
749     @Test
750     public void testKerberosSignatureInbound() throws Exception {
751         if (!runTests) {
752             System.out.println("Skipping test because kerberos server could not be started");
753             return;
754         }
755 
756         ByteArrayOutputStream baos = new ByteArrayOutputStream();
757         {
758             Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
759 
760             WSSecHeader secHeader = new WSSecHeader(doc);
761             secHeader.insertSecurityHeader();
762 
763             KerberosSecurity bst = new KerberosSecurity(doc);
764             CallbackHandler callbackHandler = new CallbackHandler() {
765                 @Override
766                 public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
767                     if (callbacks[0] instanceof PasswordCallback) {
768                         PasswordCallback passwordCallback = (PasswordCallback) callbacks[0];
769                         if (passwordCallback.getPrompt().contains("alice")) {
770                             passwordCallback.setPassword("alice".toCharArray());
771                         }
772                     }
773                 }
774             };
775             bst.retrieveServiceTicket("alice", callbackHandler, "bob@service.ws.apache.org");
776             bst.setID("Id-" + bst.hashCode());
777 
778             WSSecSignature sign = new WSSecSignature(secHeader);
779             sign.setSignatureAlgorithm(SignatureMethod.HMAC_SHA1);
780             sign.setKeyIdentifierType(WSConstants.CUSTOM_SYMM_SIGNING);
781             sign.setCustomTokenId(bst.getID());
782             sign.setCustomTokenValueType(WSConstants.WSS_GSS_KRB_V5_AP_REQ);
783 
784             SecretKey secretKey = bst.getSecretKey();
785             sign.setSecretKey(secretKey.getEncoded());
786 
787             sign.build(null);
788             WSSecurityUtil.prependChildElement(secHeader.getSecurityHeaderElement(), bst.getElement());
789 
790             javax.xml.transform.Transformer transformer = TRANSFORMER_FACTORY.newTransformer();
791             transformer.transform(new DOMSource(doc), new StreamResult(baos));
792         }
793 
794         {
795             WSSSecurityProperties securityProperties = new WSSSecurityProperties();
796             securityProperties.loadSignatureVerificationKeystore(this.getClass().getClassLoader().getResource("receiver.jks"), "default".toCharArray());
797             securityProperties.setCallbackHandler(new CallbackHandler() {
798                 @Override
799                 public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
800                     if (callbacks[0] instanceof PasswordCallback) {
801                         PasswordCallback passwordCallback = (PasswordCallback) callbacks[0];
802                         if (passwordCallback.getPrompt().contains("bob")) {
803                             passwordCallback.setPassword("bob".toCharArray());
804                         }
805                     } else if (callbacks[0] instanceof KerberosContextAndServiceNameCallback) {
806                         KerberosContextAndServiceNameCallback cb = (KerberosContextAndServiceNameCallback) callbacks[0];
807                         cb.setContextName("bob");
808                         cb.setServiceName("bob@service.ws.apache.org");
809                     }
810                 }
811             });
812 
813             final List<KerberosTokenSecurityEvent> kerberosTokenSecurityEvents = new ArrayList<>();
814 
815             InboundWSSec wsSecIn = WSSec.getInboundWSSec(securityProperties);
816             SecurityEventListener securityEventListener = new SecurityEventListener() {
817                 @Override
818                 public void registerSecurityEvent(SecurityEvent securityEvent) throws XMLSecurityException {
819                     if (securityEvent instanceof KerberosTokenSecurityEvent) {
820                         kerberosTokenSecurityEvents.add((KerberosTokenSecurityEvent) securityEvent);
821                     }
822                 }
823             };
824             XMLStreamReader xmlStreamReader = wsSecIn.processInMessage(xmlInputFactory.createXMLStreamReader(
825                     new ByteArrayInputStream(baos.toByteArray())), null, securityEventListener);
826 
827             Document document = StAX2DOM.readDoc(dbf.newDocumentBuilder(), xmlStreamReader);
828 
829             //header element must still be there
830             NodeList nodeList = document.getElementsByTagNameNS(WSSConstants.TAG_dsig_Signature.getNamespaceURI(), WSSConstants.TAG_dsig_Signature.getLocalPart());
831             assertEquals(nodeList.getLength(), 1);
832             assertEquals(nodeList.item(0).getParentNode().getLocalName(), WSSConstants.TAG_WSSE_SECURITY.getLocalPart());
833 
834             assertEquals(kerberosTokenSecurityEvents.size(), 1);
835             final KerberosTokenSecurityEvent kerberosTokenSecurityEvent = kerberosTokenSecurityEvents.get(0);
836             assertNotNull(kerberosTokenSecurityEvent.getSecurityToken().getSubject());
837             assertTrue(kerberosTokenSecurityEvent.getSecurityToken().getPrincipal() instanceof KerberosPrincipal);
838             assertEquals(kerberosTokenSecurityEvent.getSecurityToken().getPrincipal().getName(), "alice@service.ws.apache.org");
839         }
840     }
841 
842     @Test
843     public void testKerberosSignatureKIInbound() throws Exception {
844         if (!runTests) {
845             System.out.println("Skipping test because kerberos server could not be started");
846             return;
847         }
848 
849         ByteArrayOutputStream baos = new ByteArrayOutputStream();
850         {
851             Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
852 
853             WSSecHeader secHeader = new WSSecHeader(doc);
854             secHeader.insertSecurityHeader();
855 
856             KerberosSecurity bst = new KerberosSecurity(doc);
857             CallbackHandler callbackHandler = new CallbackHandler() {
858                 @Override
859                 public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
860                     if (callbacks[0] instanceof PasswordCallback) {
861                         PasswordCallback passwordCallback = (PasswordCallback) callbacks[0];
862                         if (passwordCallback.getPrompt().contains("alice")) {
863                             passwordCallback.setPassword("alice".toCharArray());
864                         }
865                     }
866                 }
867             };
868             bst.retrieveServiceTicket("alice", callbackHandler, "bob@service.ws.apache.org");
869             bst.setID("Id-" + bst.hashCode());
870 
871             WSSecSignature sign = new WSSecSignature(secHeader);
872             sign.setSignatureAlgorithm(SignatureMethod.HMAC_SHA1);
873             sign.setKeyIdentifierType(WSConstants.CUSTOM_KEY_IDENTIFIER);
874             sign.setCustomTokenValueType(WSConstants.WSS_KRB_KI_VALUE_TYPE);
875 
876             SecretKey secretKey = bst.getSecretKey();
877             byte[] keyData = secretKey.getEncoded();
878             sign.setSecretKey(keyData);
879 
880             byte[] digestBytes = KeyUtils.generateDigest(bst.getToken());
881             sign.setCustomTokenId(org.apache.xml.security.utils.XMLUtils.encodeToString(digestBytes));
882 
883             sign.build(null);
884 
885             WSSecurityUtil.prependChildElement(secHeader.getSecurityHeaderElement(), bst.getElement());
886 
887             javax.xml.transform.Transformer transformer = TRANSFORMER_FACTORY.newTransformer();
888             transformer.transform(new DOMSource(doc), new StreamResult(baos));
889         }
890 
891         {
892             WSSSecurityProperties securityProperties = new WSSSecurityProperties();
893             securityProperties.loadSignatureVerificationKeystore(this.getClass().getClassLoader().getResource("receiver.jks"), "default".toCharArray());
894             securityProperties.setCallbackHandler(new CallbackHandler() {
895                 @Override
896                 public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
897                     if (callbacks[0] instanceof PasswordCallback) {
898                         PasswordCallback passwordCallback = (PasswordCallback) callbacks[0];
899                         if (passwordCallback.getPrompt().contains("bob")) {
900                             passwordCallback.setPassword("bob".toCharArray());
901                         }
902                     } else if (callbacks[0] instanceof KerberosContextAndServiceNameCallback) {
903                         KerberosContextAndServiceNameCallback cb = (KerberosContextAndServiceNameCallback) callbacks[0];
904                         cb.setContextName("bob");
905                         cb.setServiceName("bob@service.ws.apache.org");
906                     }
907                 }
908             });
909 
910             final List<KerberosTokenSecurityEvent> kerberosTokenSecurityEvents = new ArrayList<>();
911 
912             InboundWSSec wsSecIn = WSSec.getInboundWSSec(securityProperties);
913             SecurityEventListener securityEventListener = new SecurityEventListener() {
914                 @Override
915                 public void registerSecurityEvent(SecurityEvent securityEvent) throws XMLSecurityException {
916                     if (securityEvent instanceof KerberosTokenSecurityEvent) {
917                         kerberosTokenSecurityEvents.add((KerberosTokenSecurityEvent) securityEvent);
918                     }
919                 }
920             };
921             XMLStreamReader xmlStreamReader = wsSecIn.processInMessage(xmlInputFactory.createXMLStreamReader(
922                     new ByteArrayInputStream(baos.toByteArray())), null, securityEventListener);
923 
924             Document document = StAX2DOM.readDoc(dbf.newDocumentBuilder(), xmlStreamReader);
925 
926             //header element must still be there
927             NodeList nodeList = document.getElementsByTagNameNS(WSSConstants.TAG_dsig_Signature.getNamespaceURI(), WSSConstants.TAG_dsig_Signature.getLocalPart());
928             assertEquals(nodeList.getLength(), 1);
929             assertEquals(nodeList.item(0).getParentNode().getLocalName(), WSSConstants.TAG_WSSE_SECURITY.getLocalPart());
930 
931             assertEquals(kerberosTokenSecurityEvents.size(), 1);
932         }
933     }
934 
935     @Test
936     public void testKerberosEncryptionOutbound() throws Exception {
937         if (!runTests) {
938             System.out.println("Skipping test because kerberos server could not be started");
939             return;
940         }
941 
942         Document document;
943         {
944             WSSSecurityProperties securityProperties = new WSSSecurityProperties();
945             List<WSSConstants.Action> actions = new ArrayList<>();
946             actions.add(WSSConstants.ENCRYPTION_WITH_KERBEROS_TOKEN);
947             securityProperties.setActions(actions);
948             securityProperties.setEncryptionSymAlgorithm(WSSConstants.NS_XENC_AES128);
949             securityProperties.setCallbackHandler(new CallbackHandler() {
950                 @Override
951                 public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
952                     if (callbacks[0] instanceof KerberosContextAndServiceNameCallback) {
953                         KerberosContextAndServiceNameCallback kerberosContextAndServiceNameCallback =
954                                 (KerberosContextAndServiceNameCallback) callbacks[0];
955                         kerberosContextAndServiceNameCallback.setContextName("alice");
956                         kerberosContextAndServiceNameCallback.setServiceName("bob@service.ws.apache.org");
957                     } else if (callbacks[0] instanceof PasswordCallback) {
958                         PasswordCallback passwordCallback = (PasswordCallback) callbacks[0];
959                         if (passwordCallback.getPrompt().contains("alice")) {
960                             passwordCallback.setPassword("alice".toCharArray());
961                         }
962                     }
963                 }
964             });
965 
966             ByteArrayOutputStream baos = new ByteArrayOutputStream();
967 
968             OutboundWSSec wsSecOut = WSSec.getOutboundWSSec(securityProperties);
969             XMLStreamWriter xmlStreamWriter = wsSecOut.processOutMessage(baos, StandardCharsets.UTF_8.name(), new ArrayList<>());
970             XMLStreamReader xmlStreamReader = xmlInputFactory.createXMLStreamReader(this.getClass().getClassLoader().getResourceAsStream("testdata/plain-soap-1.1.xml"));
971             XmlReaderToWriter.writeAll(xmlStreamReader, xmlStreamWriter);
972             xmlStreamWriter.close();
973 
974             document = dbf.newDocumentBuilder().parse(new ByteArrayInputStream(baos.toByteArray()));
975             NodeList nodeList = document.getElementsByTagNameNS(WSSConstants.TAG_xenc_ReferenceList.getNamespaceURI(), WSSConstants.TAG_xenc_ReferenceList.getLocalPart());
976             assertEquals(1, nodeList.getLength());
977         }
978 
979         {
980             // Configure the Validator
981             WSSConfig wssConfig = WSSConfig.getNewInstance();
982             KerberosTokenValidator validator = new KerberosTokenValidator();
983             validator.setContextName("bob");
984             validator.setServiceName("bob@service.ws.apache.org");
985             wssConfig.setValidator(WSConstants.BINARY_TOKEN, validator);
986             WSSecurityEngine secEngine = new WSSecurityEngine();
987             secEngine.setWssConfig(wssConfig);
988 
989             CallbackHandler callbackHandler = new CallbackHandler() {
990                 @Override
991                 public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
992                     if (callbacks[0] instanceof PasswordCallback) {
993                         PasswordCallback passwordCallback = (PasswordCallback) callbacks[0];
994                         if (passwordCallback.getPrompt().contains("bob")) {
995                             passwordCallback.setPassword("bob".toCharArray());
996                         }
997                     }
998                 }
999             };
1000 
1001             WSHandlerResult results =
1002                     secEngine.processSecurityHeader(document, null, callbackHandler, null);
1003             WSSecurityEngineResult actionResult =
1004                     results.getActionResults().get(WSConstants.BST).get(0);
1005             BinarySecurity token =
1006                     (BinarySecurity) actionResult.get(WSSecurityEngineResult.TAG_BINARY_SECURITY_TOKEN);
1007             assertNotNull(token);
1008 
1009             Principal principal = (Principal) actionResult.get(WSSecurityEngineResult.TAG_PRINCIPAL);
1010             assertTrue(principal instanceof KerberosPrincipal);
1011             assertTrue(principal.getName().contains("alice"));
1012         }
1013     }
1014 
1015     @Test
1016     public void testKerberosEncryptionOutboundDeprecatedTag() throws Exception {
1017         if (!runTests) {
1018             System.out.println("Skipping test because kerberos server could not be started");
1019             return;
1020         }
1021 
1022         Document document;
1023         {
1024             WSSSecurityProperties securityProperties = new WSSSecurityProperties();
1025             List<WSSConstants.Action> actions = new ArrayList<>();
1026             actions.add(WSSConstants.ENCRYPT_WITH_KERBEROS_TOKEN);
1027             securityProperties.setActions(actions);
1028             securityProperties.setEncryptionSymAlgorithm(WSSConstants.NS_XENC_AES128);
1029             securityProperties.setCallbackHandler(new CallbackHandler() {
1030                 @Override
1031                 public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
1032                     if (callbacks[0] instanceof KerberosContextAndServiceNameCallback) {
1033                         KerberosContextAndServiceNameCallback kerberosContextAndServiceNameCallback =
1034                                 (KerberosContextAndServiceNameCallback) callbacks[0];
1035                         kerberosContextAndServiceNameCallback.setContextName("alice");
1036                         kerberosContextAndServiceNameCallback.setServiceName("bob@service.ws.apache.org");
1037                     } else if (callbacks[0] instanceof PasswordCallback) {
1038                         PasswordCallback passwordCallback = (PasswordCallback) callbacks[0];
1039                         if (passwordCallback.getPrompt().contains("alice")) {
1040                             passwordCallback.setPassword("alice".toCharArray());
1041                         }
1042                     }
1043                 }
1044             });
1045 
1046             ByteArrayOutputStream baos = new ByteArrayOutputStream();
1047 
1048             OutboundWSSec wsSecOut = WSSec.getOutboundWSSec(securityProperties);
1049             XMLStreamWriter xmlStreamWriter = wsSecOut.processOutMessage(baos, StandardCharsets.UTF_8.name(), new ArrayList<>());
1050             XMLStreamReader xmlStreamReader = xmlInputFactory.createXMLStreamReader(this.getClass().getClassLoader().getResourceAsStream("testdata/plain-soap-1.1.xml"));
1051             XmlReaderToWriter.writeAll(xmlStreamReader, xmlStreamWriter);
1052             xmlStreamWriter.close();
1053 
1054             document = dbf.newDocumentBuilder().parse(new ByteArrayInputStream(baos.toByteArray()));
1055             NodeList nodeList = document.getElementsByTagNameNS(WSSConstants.TAG_xenc_ReferenceList.getNamespaceURI(), WSSConstants.TAG_xenc_ReferenceList.getLocalPart());
1056             assertEquals(1, nodeList.getLength());
1057         }
1058 
1059         {
1060             // Configure the Validator
1061             WSSConfig wssConfig = WSSConfig.getNewInstance();
1062             KerberosTokenValidator validator = new KerberosTokenValidator();
1063             validator.setContextName("bob");
1064             validator.setServiceName("bob@service.ws.apache.org");
1065             wssConfig.setValidator(WSConstants.BINARY_TOKEN, validator);
1066             WSSecurityEngine secEngine = new WSSecurityEngine();
1067             secEngine.setWssConfig(wssConfig);
1068 
1069             CallbackHandler callbackHandler = new CallbackHandler() {
1070                 @Override
1071                 public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
1072                     if (callbacks[0] instanceof PasswordCallback) {
1073                         PasswordCallback passwordCallback = (PasswordCallback) callbacks[0];
1074                         if (passwordCallback.getPrompt().contains("bob")) {
1075                             passwordCallback.setPassword("bob".toCharArray());
1076                         }
1077                     }
1078                 }
1079             };
1080 
1081             WSHandlerResult results =
1082                     secEngine.processSecurityHeader(document, null, callbackHandler, null);
1083             WSSecurityEngineResult actionResult =
1084                     results.getActionResults().get(WSConstants.BST).get(0);
1085             BinarySecurity token =
1086                     (BinarySecurity) actionResult.get(WSSecurityEngineResult.TAG_BINARY_SECURITY_TOKEN);
1087             assertNotNull(token);
1088 
1089             Principal principal = (Principal) actionResult.get(WSSecurityEngineResult.TAG_PRINCIPAL);
1090             assertTrue(principal instanceof KerberosPrincipal);
1091             assertTrue(principal.getName().contains("alice"));
1092         }
1093     }
1094 
1095     @Test
1096     public void testKerberosEncryptionInbound() throws Exception {
1097         if (!runTests) {
1098             System.out.println("Skipping test because kerberos server could not be started");
1099             return;
1100         }
1101 
1102         ByteArrayOutputStream baos = new ByteArrayOutputStream();
1103         {
1104             Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
1105 
1106             WSSecHeader secHeader = new WSSecHeader(doc);
1107             secHeader.insertSecurityHeader();
1108 
1109             KerberosSecurity bst = new KerberosSecurity(doc);
1110             CallbackHandler callbackHandler = new CallbackHandler() {
1111                 @Override
1112                 public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
1113                     if (callbacks[0] instanceof PasswordCallback) {
1114                         PasswordCallback passwordCallback = (PasswordCallback) callbacks[0];
1115                         if (passwordCallback.getPrompt().contains("alice")) {
1116                             passwordCallback.setPassword("alice".toCharArray());
1117                         }
1118                     }
1119                 }
1120             };
1121             bst.retrieveServiceTicket("alice", callbackHandler, "bob@service.ws.apache.org");
1122             bst.setID("Id-" + bst.hashCode());
1123 
1124             WSSecEncrypt builder = new WSSecEncrypt(secHeader);
1125             builder.setSymmetricEncAlgorithm(WSConstants.AES_256);
1126             SecretKey secretKey = bst.getSecretKey();
1127             builder.setEncryptSymmKey(false);
1128             builder.setCustomReferenceValue(WSConstants.WSS_GSS_KRB_V5_AP_REQ);
1129             builder.setEncKeyId(bst.getID());
1130             builder.build(null, secretKey);
1131             WSSecurityUtil.prependChildElement(secHeader.getSecurityHeaderElement(), bst.getElement());
1132 
1133             javax.xml.transform.Transformer transformer = TRANSFORMER_FACTORY.newTransformer();
1134             transformer.transform(new DOMSource(doc), new StreamResult(baos));
1135         }
1136 
1137         {
1138             WSSSecurityProperties securityProperties = new WSSSecurityProperties();
1139             securityProperties.loadDecryptionKeystore(this.getClass().getClassLoader().getResource("receiver.jks"), "default".toCharArray());
1140             securityProperties.setCallbackHandler(new CallbackHandler() {
1141                 @Override
1142                 public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
1143                     if (callbacks[0] instanceof PasswordCallback) {
1144                         PasswordCallback passwordCallback = (PasswordCallback) callbacks[0];
1145                         if (passwordCallback.getPrompt().contains("bob")) {
1146                             passwordCallback.setPassword("bob".toCharArray());
1147                         }
1148                     } else if (callbacks[0] instanceof KerberosContextAndServiceNameCallback) {
1149                         KerberosContextAndServiceNameCallback cb = (KerberosContextAndServiceNameCallback) callbacks[0];
1150                         cb.setContextName("bob");
1151                         cb.setServiceName("bob@service.ws.apache.org");
1152                     }
1153                 }
1154             });
1155 
1156             final List<KerberosTokenSecurityEvent> kerberosTokenSecurityEvents = new ArrayList<>();
1157 
1158             InboundWSSec wsSecIn = WSSec.getInboundWSSec(securityProperties);
1159             SecurityEventListener securityEventListener = new SecurityEventListener() {
1160                 @Override
1161                 public void registerSecurityEvent(SecurityEvent securityEvent) throws XMLSecurityException {
1162                     if (securityEvent instanceof KerberosTokenSecurityEvent) {
1163                         kerberosTokenSecurityEvents.add((KerberosTokenSecurityEvent) securityEvent);
1164                     }
1165                 }
1166             };
1167             XMLStreamReader xmlStreamReader = wsSecIn.processInMessage(xmlInputFactory.createXMLStreamReader(
1168                     new ByteArrayInputStream(baos.toByteArray())), null, securityEventListener);
1169 
1170             Document document = StAX2DOM.readDoc(dbf.newDocumentBuilder(), xmlStreamReader);
1171 
1172             //header element must still be there
1173             NodeList nodeList = document.getElementsByTagNameNS(WSSConstants.TAG_WSSE_BINARY_SECURITY_TOKEN.getNamespaceURI(), WSSConstants.TAG_WSSE_BINARY_SECURITY_TOKEN.getLocalPart());
1174             assertEquals(nodeList.getLength(), 1);
1175             assertEquals(nodeList.item(0).getParentNode().getLocalName(), WSSConstants.TAG_WSSE_SECURITY.getLocalPart());
1176 
1177             //no encrypted content
1178             nodeList = document.getElementsByTagNameNS(WSSConstants.TAG_xenc_EncryptedData.getNamespaceURI(), WSSConstants.TAG_xenc_EncryptedData.getLocalPart());
1179             assertEquals(nodeList.getLength(), 0);
1180 
1181             assertEquals(kerberosTokenSecurityEvents.size(), 1);
1182         }
1183     }
1184 
1185     @Test
1186     public void testKerberosEncryptionKIInbound() throws Exception {
1187         if (!runTests) {
1188             System.out.println("Skipping test because kerberos server could not be started");
1189             return;
1190         }
1191 
1192         ByteArrayOutputStream baos = new ByteArrayOutputStream();
1193         {
1194             Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
1195 
1196             WSSecHeader secHeader = new WSSecHeader(doc);
1197             secHeader.insertSecurityHeader();
1198 
1199             KerberosSecurity bst = new KerberosSecurity(doc);
1200             CallbackHandler callbackHandler = new CallbackHandler() {
1201                 @Override
1202                 public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
1203                     if (callbacks[0] instanceof PasswordCallback) {
1204                         PasswordCallback passwordCallback = (PasswordCallback) callbacks[0];
1205                         if (passwordCallback.getPrompt().contains("alice")) {
1206                             passwordCallback.setPassword("alice".toCharArray());
1207                         }
1208                     }
1209                 }
1210             };
1211             bst.retrieveServiceTicket("alice", callbackHandler, "bob@service.ws.apache.org");
1212             bst.setID("Id-" + bst.hashCode());
1213 
1214             WSSecEncrypt builder = new WSSecEncrypt(secHeader);
1215             builder.setSymmetricEncAlgorithm(WSConstants.AES_128);
1216             SecretKey secretKey = bst.getSecretKey();
1217             builder.setEncryptSymmKey(false);
1218             builder.setCustomReferenceValue(WSConstants.WSS_KRB_KI_VALUE_TYPE);
1219 
1220             byte[] digestBytes = KeyUtils.generateDigest(bst.getToken());
1221             builder.setEncKeyId(org.apache.xml.security.utils.XMLUtils.encodeToString(digestBytes));
1222 
1223             builder.build(null, secretKey);
1224 
1225             WSSecurityUtil.prependChildElement(secHeader.getSecurityHeaderElement(), bst.getElement());
1226 
1227             javax.xml.transform.Transformer transformer = TRANSFORMER_FACTORY.newTransformer();
1228             transformer.transform(new DOMSource(doc), new StreamResult(baos));
1229 
1230         }
1231 
1232         {
1233             WSSSecurityProperties securityProperties = new WSSSecurityProperties();
1234             securityProperties.loadDecryptionKeystore(this.getClass().getClassLoader().getResource("receiver.jks"), "default".toCharArray());
1235             securityProperties.setCallbackHandler(new CallbackHandler() {
1236                 @Override
1237                 public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
1238                     if (callbacks[0] instanceof PasswordCallback) {
1239                         PasswordCallback passwordCallback = (PasswordCallback) callbacks[0];
1240                         if (passwordCallback.getPrompt().contains("bob")) {
1241                             passwordCallback.setPassword("bob".toCharArray());
1242                         }
1243                     } else if (callbacks[0] instanceof KerberosContextAndServiceNameCallback) {
1244                         KerberosContextAndServiceNameCallback cb = (KerberosContextAndServiceNameCallback) callbacks[0];
1245                         cb.setContextName("bob");
1246                         cb.setServiceName("bob@service.ws.apache.org");
1247                     }
1248                 }
1249             });
1250 
1251             final List<KerberosTokenSecurityEvent> kerberosTokenSecurityEvents = new ArrayList<>();
1252 
1253             InboundWSSec wsSecIn = WSSec.getInboundWSSec(securityProperties);
1254             SecurityEventListener securityEventListener = new SecurityEventListener() {
1255                 @Override
1256                 public void registerSecurityEvent(SecurityEvent securityEvent) throws XMLSecurityException {
1257                     if (securityEvent instanceof KerberosTokenSecurityEvent) {
1258                         kerberosTokenSecurityEvents.add((KerberosTokenSecurityEvent) securityEvent);
1259                     }
1260                 }
1261             };
1262             XMLStreamReader xmlStreamReader = wsSecIn.processInMessage(xmlInputFactory.createXMLStreamReader(
1263                     new ByteArrayInputStream(baos.toByteArray())), null, securityEventListener);
1264 
1265             Document document = StAX2DOM.readDoc(dbf.newDocumentBuilder(), xmlStreamReader);
1266 
1267             //header element must still be there
1268             NodeList nodeList = document.getElementsByTagNameNS(WSSConstants.TAG_WSSE_BINARY_SECURITY_TOKEN.getNamespaceURI(), WSSConstants.TAG_WSSE_BINARY_SECURITY_TOKEN.getLocalPart());
1269             assertEquals(nodeList.getLength(), 1);
1270             assertEquals(nodeList.item(0).getParentNode().getLocalName(), WSSConstants.TAG_WSSE_SECURITY.getLocalPart());
1271 
1272             //no encrypted content
1273             nodeList = document.getElementsByTagNameNS(WSSConstants.TAG_xenc_EncryptedData.getNamespaceURI(), WSSConstants.TAG_xenc_EncryptedData.getLocalPart());
1274             assertEquals(nodeList.getLength(), 0);
1275 
1276             assertEquals(kerberosTokenSecurityEvents.size(), 1);
1277         }
1278     }
1279 
1280 }