001: /**
002: * Licensed to the Apache Software Foundation (ASF) under one
003: * or more contributor license agreements. See the NOTICE file
004: * distributed with this work for additional information
005: * regarding copyright ownership. The ASF licenses this file
006: * to you under the Apache License, Version 2.0 (the
007: * "License"); you may not use this file except in compliance
008: * with the License. You may obtain a copy of the License at
009: *
010: * http://www.apache.org/licenses/LICENSE-2.0
011: *
012: * Unless required by applicable law or agreed to in writing,
013: * software distributed under the License is distributed on an
014: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015: * KIND, either express or implied. See the License for the
016: * specific language governing permissions and limitations
017: * under the License.
018: */package org.apache.cxf.systest.http;
019:
020: import java.io.FileInputStream;
021: import java.io.IOException;
022: import java.net.URL;
023: import java.security.GeneralSecurityException;
024: import java.security.KeyStore;
025: import java.util.ArrayList;
026: import java.util.List;
027: import java.util.Map;
028: import java.util.TreeMap;
029:
030: import javax.net.ssl.KeyManager;
031: import javax.net.ssl.KeyManagerFactory;
032: import javax.net.ssl.TrustManager;
033: import javax.net.ssl.TrustManagerFactory;
034: import javax.xml.namespace.QName;
035:
036: import org.apache.cxf.Bus;
037: import org.apache.cxf.BusFactory;
038: import org.apache.cxf.bus.spring.SpringBusFactory;
039: import org.apache.cxf.configuration.jsse.TLSClientParameters;
040: import org.apache.cxf.configuration.security.AuthorizationPolicy;
041: import org.apache.cxf.configuration.security.FiltersType;
042: import org.apache.cxf.endpoint.Client;
043: import org.apache.cxf.frontend.ClientProxy;
044: import org.apache.cxf.message.Message;
045: import org.apache.cxf.testutil.common.AbstractBusClientServerTestBase;
046:
047: import org.apache.cxf.transport.http.HTTPConduit;
048: import org.apache.cxf.transport.http.HttpBasicAuthSupplier;
049: import org.apache.cxf.transport.http.MessageTrustDecider;
050: import org.apache.cxf.transport.http.URLConnectionInfo;
051: import org.apache.cxf.transport.http.UntrustedURLConnectionIOException;
052:
053: import org.apache.cxf.transport.https.HttpsURLConnectionInfo;
054:
055: import org.apache.cxf.transports.http.configuration.HTTPClientPolicy;
056:
057: import org.apache.hello_world.Greeter;
058: import org.apache.hello_world.services.SOAPService;
059:
060: import org.junit.Before;
061: import org.junit.Test;
062:
063: /**
064: * This class tests several issues and Conduit policies based
065: * on a set up of redirecting servers.
066: * <pre>
067: *
068: * Http Redirection:
069: *
070: * Rethwel(http:9004) ------\
071: * ----> Mortimer (http:9000)
072: * Poltim(https:9005) ------/
073: *
074: * HttpS redirection/Trust:
075: *
076: * Tarpin(https:9003) ----> Gordy(https:9001) ----> Bethal(https:9002)
077: *
078: * Redirect Loop:
079: *
080: * Hurlon (http:9006) ----> Abost(http:9007) ----\
081: * ^ |
082: * |-------------------------------------------/
083: *
084: * Hostname Verifier Test
085: *
086: * Morpit (https:9008)
087: *
088: * </pre>
089: * The Bethal server issues 401 with differing realms depending on the
090: * User name given in the authorization header.
091: * <p>
092: * The Morpit has a CN that is not equal to "localhost" to kick in
093: * the Hostname Verifier.
094: */
095: public class HTTPConduitTest extends AbstractBusClientServerTestBase {
096:
097: private static final boolean IN_PROCESS = true;
098:
099: private static TLSClientParameters tlsClientParameters = new TLSClientParameters();
100: private static Map<String, String> addrMap = new TreeMap<String, String>();
101: private static List<String> servers = new ArrayList<String>();
102:
103: static {
104: addrMap.put("Mortimer", "http://localhost:9000/");
105: addrMap.put("Tarpin", "https://localhost:9003/");
106: addrMap.put("Rethwel", "http://localhost:9004/");
107: addrMap.put("Poltim", "https://localhost:9005/");
108: addrMap.put("Gordy", "https://localhost:9001/");
109: addrMap.put("Bethal", "https://localhost:9002/");
110: addrMap.put("Abost", "http://localhost:9007/");
111: addrMap.put("Hurlon", "http://localhost:9006/");
112: addrMap.put("Morpit", "https://localhost:9008/");
113: }
114:
115: static {
116: try {
117: //System.setProperty("javax.net.debug", "all");
118: String keystore = Server.class.getResource(
119: "resources/Morpit.jks").getFile();
120: //System.out.println("Keystore: " + keystore);
121: KeyManager[] kmgrs = getKeyManagers(getKeyStore("JKS",
122: keystore, "password"), "password");
123:
124: String truststore = Server.class.getResource(
125: "resources/Truststore.jks").getFile();
126: //System.out.println("Truststore: " + truststore);
127: TrustManager[] tmgrs = getTrustManagers(getKeyStore("JKS",
128: truststore, "password"));
129:
130: tlsClientParameters.setKeyManagers(kmgrs);
131: tlsClientParameters.setTrustManagers(tmgrs);
132: FiltersType filters = new FiltersType();
133: filters.getInclude().add(".*_EXPORT_.*");
134: filters.getInclude().add(".*_EXPORT1024_.*");
135: filters.getInclude().add(".*_WITH_DES_.*");
136: filters.getInclude().add(".*_WITH_NULL_.*");
137: filters.getInclude().add(".*_DH_anon_.*");
138: tlsClientParameters.setCipherSuitesFilter(filters);
139: } catch (Exception e) {
140: throw new RuntimeException("Static initialization failed",
141: e);
142: }
143: }
144:
145: private final QName serviceName = new QName(
146: "http://apache.org/hello_world", "SOAPService");
147: private final QName bethalQ = new QName(
148: "http://apache.org/hello_world", "Bethal");
149: private final QName gordyQ = new QName(
150: "http://apache.org/hello_world", "Gordy");
151: private final QName tarpinQ = new QName(
152: "http://apache.org/hello_world", "Tarpin");
153: private final QName rethwelQ = new QName(
154: "http://apache.org/hello_world", "Rethwel");
155: private final QName mortimerQ = new QName(
156: "http://apache.org/hello_world", "Mortimer");
157: private final QName poltimQ = new QName(
158: "http://apache.org/hello_world", "Poltim");
159: private final QName hurlonQ = new QName(
160: "http://apache.org/hello_world", "Hurlon");
161:
162: // PMD Violation because it is not used, but
163: // it is here for completeness.
164: //private final QName abostQ =
165: //new QName("http://apache.org/hello_world", "Abost");
166: public HTTPConduitTest() {
167: }
168:
169: /**
170: * This function is used to start up a server. It only "starts" a
171: * server if it hasn't been started before, hence its static nature.
172: * <p>
173: * This approach is used to start the needed servers for a particular test
174: * instead of starting them all in "startServers". This single needed
175: * server approach allieviates the pain in starting them all just to run
176: * a particular test in the debugger.
177: */
178: public static synchronized boolean startServer(String name) {
179: if (servers.contains(name)) {
180: return true;
181: }
182: URL serverC = Server.class.getResource("resources/" + name
183: + ".cxf");
184: boolean server = launchServer(Server.class, null, new String[] {
185: name, addrMap.get(name), serverC.toString() },
186: IN_PROCESS);
187: if (server) {
188: servers.add(name);
189: }
190: return server;
191: }
192:
193: @Before
194: public void setUp() {
195: // TODO: Do I need this?
196: System.setProperty("org.apache.cxf.bus.factory",
197: "org.apache.cxf.bus.CXFBusFactory");
198: }
199:
200: public static KeyStore getKeyStore(String ksType, String file,
201: String ksPassword) throws GeneralSecurityException,
202: IOException {
203:
204: String type = ksType != null ? ksType : KeyStore
205: .getDefaultType();
206:
207: char[] password = ksPassword != null ? ksPassword.toCharArray()
208: : null;
209:
210: // We just use the default Keystore provider
211: KeyStore keyStore = KeyStore.getInstance(type);
212:
213: keyStore.load(new FileInputStream(file), password);
214:
215: return keyStore;
216: }
217:
218: public static KeyManager[] getKeyManagers(KeyStore keyStore,
219: String keyPassword) throws GeneralSecurityException,
220: IOException {
221: // For tests, we just use the default algorithm
222: String alg = KeyManagerFactory.getDefaultAlgorithm();
223:
224: char[] keyPass = keyPassword != null ? keyPassword
225: .toCharArray() : null;
226:
227: // For tests, we just use the default provider.
228: KeyManagerFactory fac = KeyManagerFactory.getInstance(alg);
229:
230: fac.init(keyStore, keyPass);
231:
232: return fac.getKeyManagers();
233: }
234:
235: public static TrustManager[] getTrustManagers(KeyStore keyStore)
236: throws GeneralSecurityException, IOException {
237: // For tests, we just use the default algorithm
238: String alg = TrustManagerFactory.getDefaultAlgorithm();
239:
240: // For tests, we just use the default provider.
241: TrustManagerFactory fac = TrustManagerFactory.getInstance(alg);
242:
243: fac.init(keyStore);
244:
245: return fac.getTrustManagers();
246: }
247:
248: @Test
249: public void testBasicConnection() throws Exception {
250: startServer("Mortimer");
251: URL wsdl = getClass().getResource("resources/greeting.wsdl");
252: assertNotNull("WSDL is null", wsdl);
253:
254: SOAPService service = new SOAPService(wsdl, serviceName);
255: assertNotNull("Service is null", service);
256:
257: Greeter mortimer = service.getPort(mortimerQ, Greeter.class);
258: assertNotNull("Port is null", mortimer);
259:
260: String answer = mortimer.sayHi();
261: assertTrue("Unexpected answer: " + answer,
262: "Bonjour from Mortimer".equals(answer));
263: }
264:
265: /**
266: * This methods tests that a conduit that is not configured
267: * to follow redirects will not. The default is not to
268: * follow redirects.
269: * Rethwel redirects to Mortimer.
270: *
271: * Note: Unfortunately, the invocation will
272: * "fail" for any number of other reasons.
273: *
274: */
275: @Test
276: public void testHttp2HttpRedirectFail() throws Exception {
277: startServer("Mortimer");
278: startServer("Rethwel");
279:
280: URL wsdl = getClass().getResource("resources/greeting.wsdl");
281: assertNotNull("WSDL is null", wsdl);
282:
283: SOAPService service = new SOAPService(wsdl, serviceName);
284: assertNotNull("Service is null", service);
285:
286: Greeter rethwel = service.getPort(rethwelQ, Greeter.class);
287: assertNotNull("Port is null", rethwel);
288:
289: String answer = null;
290: try {
291: answer = rethwel.sayHi();
292: fail("Redirect didn't fail. Got answer: " + answer);
293: } catch (Exception e) {
294: //e.printStackTrace();
295: }
296:
297: }
298:
299: /**
300: * We use this class to reset the default bus.
301: * Note: This may not always work in the future.
302: * I was lucky in that "defaultBus" is actually a
303: * protected static.
304: */
305: class DefaultBusFactory extends SpringBusFactory {
306: public Bus createBus(URL config) {
307: Bus bus = super .createBus(config, true);
308: BusFactory.setDefaultBus(bus);
309: BusFactory.setThreadDefaultBus(bus);
310: return bus;
311: }
312: }
313:
314: /**
315: * This method tests if http to http redirects work.
316: * Rethwel redirects to Mortimer.
317: */
318: @Test
319: public void testHttp2HttpRedirect() throws Exception {
320: startServer("Mortimer");
321: startServer("Rethwel");
322:
323: URL config = getClass().getResource(
324: "resources/Http2HttpRedirect.cxf");
325:
326: // We go through the back door, setting the default bus.
327: new DefaultBusFactory().createBus(config);
328:
329: URL wsdl = getClass().getResource("resources/greeting.wsdl");
330: assertNotNull("WSDL is null", wsdl);
331:
332: SOAPService service = new SOAPService(wsdl, serviceName);
333: assertNotNull("Service is null", service);
334:
335: Greeter rethwel = service.getPort(rethwelQ, Greeter.class);
336: assertNotNull("Port is null", rethwel);
337:
338: String answer = rethwel.sayHi();
339: assertTrue("Unexpected answer: " + answer,
340: "Bonjour from Mortimer".equals(answer));
341: }
342:
343: /**
344: * This methods tests that a redirection loop will fail.
345: * Hurlon redirects to Abost, which redirects to Hurlon.
346: *
347: * Note: Unfortunately, the invocation may "fail" for any
348: * number of reasons.
349: */
350: @Test
351: public void testHttp2HttpLoopRedirectFail() throws Exception {
352: startServer("Abost");
353: startServer("Hurlon");
354:
355: URL config = getClass().getResource(
356: "resources/Http2HttpLoopRedirectFail.cxf");
357:
358: // We go through the back door, setting the default bus.
359: new DefaultBusFactory().createBus(config);
360:
361: URL wsdl = getClass().getResource("resources/greeting.wsdl");
362: assertNotNull("WSDL is null", wsdl);
363:
364: SOAPService service = new SOAPService(wsdl, serviceName);
365: assertNotNull("Service is null", service);
366:
367: Greeter hurlon = service.getPort(hurlonQ, Greeter.class);
368: assertNotNull("Port is null", hurlon);
369:
370: String answer = null;
371: try {
372: answer = hurlon.sayHi();
373: fail("Redirect didn't fail. Got answer: " + answer);
374: } catch (Exception e) {
375: // This exception will be one of not being able to
376: // read from the StreamReader
377: //e.printStackTrace();
378: }
379:
380: }
381:
382: /**
383: * This methods tests a basic https connection to Bethal.
384: * It supplies an authorization policy with premetive user/pass
385: * to avoid the 401.
386: */
387: @Test
388: public void testHttpsBasicConnectionWithConfig() throws Exception {
389: startServer("Bethal");
390:
391: URL config = getClass().getResource(
392: "resources/BethalClientConfig.cxf");
393:
394: // We go through the back door, setting the default bus.
395: new DefaultBusFactory().createBus(config);
396: URL wsdl = getClass().getResource("resources/greeting.wsdl");
397: assertNotNull("WSDL is null", wsdl);
398:
399: SOAPService service = new SOAPService(wsdl, serviceName);
400: assertNotNull("Service is null", service);
401:
402: Greeter bethal = service.getPort(bethalQ, Greeter.class);
403: assertNotNull("Port is null", bethal);
404:
405: // Okay, I'm sick of configuration files.
406: // This also tests dynamic configuration of the conduit.
407: Client client = ClientProxy.getClient(bethal);
408: HTTPConduit http = (HTTPConduit) client.getConduit();
409:
410: HTTPClientPolicy httpClientPolicy = new HTTPClientPolicy();
411:
412: httpClientPolicy.setAutoRedirect(false);
413: // If we set any name, but Edward, Mary, or George,
414: // and a password of "password" we will get through
415: // Bethal.
416: AuthorizationPolicy authPolicy = new AuthorizationPolicy();
417: authPolicy.setUserName("Betty");
418: authPolicy.setPassword("password");
419:
420: http.setClient(httpClientPolicy);
421: http.setTlsClientParameters(tlsClientParameters);
422: http.setAuthorization(authPolicy);
423:
424: String answer = bethal.sayHi();
425: assertTrue("Unexpected answer: " + answer,
426: "Bonjour from Bethal".equals(answer));
427: }
428:
429: /**
430: * This methods tests a basic https connection to Bethal.
431: * It supplies an authorization policy with premetive user/pass
432: * to avoid the 401.
433: */
434: @Test
435: public void testHttpsBasicConnection() throws Exception {
436: startServer("Bethal");
437:
438: URL wsdl = getClass().getResource("resources/greeting.wsdl");
439: assertNotNull("WSDL is null", wsdl);
440:
441: SOAPService service = new SOAPService(wsdl, serviceName);
442: assertNotNull("Service is null", service);
443:
444: Greeter bethal = service.getPort(bethalQ, Greeter.class);
445: assertNotNull("Port is null", bethal);
446:
447: // Okay, I'm sick of configuration files.
448: // This also tests dynamic configuration of the conduit.
449: Client client = ClientProxy.getClient(bethal);
450: HTTPConduit http = (HTTPConduit) client.getConduit();
451:
452: HTTPClientPolicy httpClientPolicy = new HTTPClientPolicy();
453:
454: httpClientPolicy.setAutoRedirect(false);
455: // If we set any name, but Edward, Mary, or George,
456: // and a password of "password" we will get through
457: // Bethal.
458: AuthorizationPolicy authPolicy = new AuthorizationPolicy();
459: authPolicy.setUserName("Betty");
460: authPolicy.setPassword("password");
461:
462: http.setClient(httpClientPolicy);
463: http.setTlsClientParameters(tlsClientParameters);
464: http.setAuthorization(authPolicy);
465:
466: String answer = bethal.sayHi();
467: assertTrue("Unexpected answer: " + answer,
468: "Bonjour from Bethal".equals(answer));
469: }
470:
471: /**
472: * This test should fail when we hit Poltim, since it redirects
473: * to Mortimer, which is an http url, and Poltim is an https server.
474: */
475: @Test
476: public void testHttpsRedirectToHttpFail() throws Exception {
477: startServer("Mortimer");
478: startServer("Poltim");
479:
480: URL wsdl = getClass().getResource("resources/greeting.wsdl");
481: assertNotNull("WSDL is null", wsdl);
482:
483: SOAPService service = new SOAPService(wsdl, serviceName);
484: assertNotNull("Service is null", service);
485:
486: Greeter poltim = service.getPort(poltimQ, Greeter.class);
487: assertNotNull("Port is null", poltim);
488:
489: // Okay, I'm sick of configuration files.
490: // This also tests dynamic configuration of the conduit.
491: Client client = ClientProxy.getClient(poltim);
492: HTTPConduit http = (HTTPConduit) client.getConduit();
493:
494: HTTPClientPolicy httpClientPolicy = new HTTPClientPolicy();
495:
496: httpClientPolicy.setAutoRedirect(true);
497:
498: http.setClient(httpClientPolicy);
499: http.setTlsClientParameters(tlsClientParameters);
500:
501: try {
502: String answer = poltim.sayHi();
503: fail("Unexpected answer from Poltim: " + answer);
504: } catch (Exception e) {
505: //e.printStackTrace();
506: }
507: }
508:
509: class MyHttpsTrustDecider extends MessageTrustDecider {
510:
511: private String[] trustName;
512: private int called;
513:
514: MyHttpsTrustDecider(String name) {
515: trustName = new String[] { name };
516: }
517:
518: MyHttpsTrustDecider(String[] name) {
519: trustName = name;
520: }
521:
522: public int wasCalled() {
523: return called;
524: }
525:
526: public void establishTrust(String conduitName,
527: URLConnectionInfo cinfo, Message message)
528: throws UntrustedURLConnectionIOException {
529:
530: called++;
531:
532: HttpsURLConnectionInfo ci = (HttpsURLConnectionInfo) cinfo;
533: boolean trusted = false;
534: for (int i = 0; i < trustName.length; i++) {
535: trusted = trusted
536: || ci.getPeerPrincipal().toString().contains(
537: "OU=" + trustName[i]);
538: }
539: if (!trusted) {
540: throw new UntrustedURLConnectionIOException(
541: "Peer Principal \"" + ci.getPeerPrincipal()
542: + "\" does not contain "
543: + getTrustNames());
544: }
545: }
546:
547: private String getTrustNames() {
548: StringBuffer sb = new StringBuffer();
549: for (int i = 0; i < trustName.length; i++) {
550: sb.append("\"OU=");
551: sb.append(trustName[i]);
552: sb.append("\"");
553: if (i < trustName.length - 1) {
554: sb.append(", ");
555: }
556: }
557: return sb.toString();
558: }
559: }
560:
561: @Test
562: public void testHttpsTrust() throws Exception {
563: startServer("Bethal");
564:
565: URL wsdl = getClass().getResource("resources/greeting.wsdl");
566: assertNotNull("WSDL is null", wsdl);
567:
568: SOAPService service = new SOAPService(wsdl, serviceName);
569: assertNotNull("Service is null", service);
570:
571: Greeter bethal = service.getPort(bethalQ, Greeter.class);
572: assertNotNull("Port is null", bethal);
573:
574: // Okay, I'm sick of configuration files.
575: // This also tests dynamic configuration of the conduit.
576: Client client = ClientProxy.getClient(bethal);
577: HTTPConduit http = (HTTPConduit) client.getConduit();
578:
579: HTTPClientPolicy httpClientPolicy = new HTTPClientPolicy();
580:
581: httpClientPolicy.setAutoRedirect(false);
582: // If we set any name, but Edward, Mary, or George,
583: // and a password of "password" we will get through
584: // Bethal.
585: AuthorizationPolicy authPolicy = new AuthorizationPolicy();
586: authPolicy.setUserName("Betty");
587: authPolicy.setPassword("password");
588:
589: http.setClient(httpClientPolicy);
590: http.setTlsClientParameters(tlsClientParameters);
591: http.setAuthorization(authPolicy);
592:
593: // Our expected server should be OU=Bethal
594: http.setTrustDecider(new MyHttpsTrustDecider("Bethal"));
595:
596: String answer = bethal.sayHi();
597: assertTrue("Unexpected answer: " + answer,
598: "Bonjour from Bethal".equals(answer));
599:
600: // Nobody will not equal OU=Bethal
601: MyHttpsTrustDecider trustDecider = new MyHttpsTrustDecider(
602: "Nobody");
603: http.setTrustDecider(trustDecider);
604: try {
605: answer = bethal.sayHi();
606: fail("Unexpected answer from Bethal: " + answer);
607: } catch (Exception e) {
608: //e.printStackTrace();
609: //assertTrue("Trust Decider was not called",
610: // 0 > trustDecider.wasCalled());
611: }
612: }
613:
614: @Test
615: public void testHttpsTrustRedirect() throws Exception {
616: startServer("Tarpin");
617: startServer("Gordy");
618: startServer("Bethal");
619:
620: URL wsdl = getClass().getResource("resources/greeting.wsdl");
621: assertNotNull("WSDL is null", wsdl);
622:
623: SOAPService service = new SOAPService(wsdl, serviceName);
624: assertNotNull("Service is null", service);
625:
626: Greeter tarpin = service.getPort(tarpinQ, Greeter.class);
627: assertNotNull("Port is null", tarpin);
628:
629: // Okay, I'm sick of configuration files.
630: // This also tests dynamic configuration of the conduit.
631: Client client = ClientProxy.getClient(tarpin);
632: HTTPConduit http = (HTTPConduit) client.getConduit();
633:
634: HTTPClientPolicy httpClientPolicy = new HTTPClientPolicy();
635:
636: httpClientPolicy.setAutoRedirect(true);
637: // If we set any name, but Edward, Mary, or George,
638: // and a password of "password" we will get through
639: // Bethal.
640: AuthorizationPolicy authPolicy = new AuthorizationPolicy();
641: authPolicy.setUserName("Betty");
642: authPolicy.setPassword("password");
643:
644: http.setClient(httpClientPolicy);
645: http.setTlsClientParameters(tlsClientParameters);
646: http.setAuthorization(authPolicy);
647:
648: // We get redirected from Tarpin, to Gordy, to Bethal.
649: MyHttpsTrustDecider trustDecider = new MyHttpsTrustDecider(
650: new String[] { "Tarpin", "Gordy", "Bethal" });
651: http.setTrustDecider(trustDecider);
652:
653: // We actually get our answer from Bethal at the end of the
654: // redirects.
655: String answer = tarpin.sayHi();
656:
657: assertTrue("Trust Decider wasn't called correctly",
658: 3 == trustDecider.wasCalled());
659: assertTrue("Unexpected answer: " + answer,
660: "Bonjour from Bethal".equals(answer));
661:
662: // Limit the redirects to 1, since there are two, this should fail.
663: http.getClient().setMaxRetransmits(1);
664:
665: try {
666: answer = tarpin.sayHi();
667: fail("Unexpected answer from Tarpin: " + answer);
668: } catch (Exception e) {
669: //e.printStackTrace();
670: }
671:
672: // Set back to unlimited.
673: http.getClient().setMaxRetransmits(-1);
674:
675: // Effectively we will not trust Gordy in the middle.
676: trustDecider = new MyHttpsTrustDecider(new String[] { "Tarpin",
677: "Bethal" });
678: http.setTrustDecider(trustDecider);
679:
680: try {
681: answer = tarpin.sayHi();
682: fail("Unexpected answer from Tarpin: " + answer);
683: } catch (Exception e) {
684: //e.printStackTrace();
685: assertTrue("Trust Decider wasn't called correctly",
686: 2 == trustDecider.wasCalled());
687: }
688:
689: }
690:
691: public class MyBasicAuthSupplier extends HttpBasicAuthSupplier {
692:
693: String realm;
694: String user;
695: String pass;
696:
697: /**
698: * This will loop from Cronus, to Andromeda, to Zorantius
699: */
700: MyBasicAuthSupplier() {
701: }
702:
703: MyBasicAuthSupplier(String r, String u, String p) {
704: realm = r;
705: user = u;
706: pass = p;
707: }
708:
709: @Override
710: public UserPass getPreemptiveUserPass(String conduitName,
711: URL currentURL, Message message) {
712: return null;
713: }
714:
715: /**
716: * If we don't have the realm set, then we loop
717: * through the realms.
718: */
719: @Override
720: public UserPass getUserPassForRealm(String conduitName,
721: URL currentURL, Message message, String reqestedRealm) {
722: if (realm != null && realm.equals(reqestedRealm)) {
723: return createUserPass(user, pass);
724: }
725: if ("Andromeda".equals(reqestedRealm)) {
726: // This will get us another 401 to Zorantius
727: return createUserPass("Edward", "password");
728: }
729: if ("Zorantius".equals(reqestedRealm)) {
730: // George will get us another 401 to Cronus
731: return createUserPass("George", "password");
732: }
733: if ("Cronus".equals(reqestedRealm)) {
734: // Mary will get us another 401 to Andromeda
735: return createUserPass("Mary", "password");
736: }
737: return null;
738: }
739:
740: }
741:
742: /**
743: * This tests redirects through Gordy to Bethal. Bethal will
744: * supply a series of 401s. See PushBack401.
745: */
746: @Test
747: public void testHttpsRedirect401Response() throws Exception {
748: startServer("Gordy");
749: startServer("Bethal");
750:
751: URL wsdl = getClass().getResource("resources/greeting.wsdl");
752: assertNotNull("WSDL is null", wsdl);
753:
754: SOAPService service = new SOAPService(wsdl, serviceName);
755: assertNotNull("Service is null", service);
756:
757: Greeter gordy = service.getPort(gordyQ, Greeter.class);
758: assertNotNull("Port is null", gordy);
759:
760: // Okay, I'm sick of configuration files.
761: // This also tests dynamic configuration of the conduit.
762: Client client = ClientProxy.getClient(gordy);
763: HTTPConduit http = (HTTPConduit) client.getConduit();
764:
765: HTTPClientPolicy httpClientPolicy = new HTTPClientPolicy();
766:
767: httpClientPolicy.setAutoRedirect(true);
768: http.setClient(httpClientPolicy);
769: http.setTlsClientParameters(tlsClientParameters);
770:
771: // We get redirected from Gordy, to Bethal.
772: http.setTrustDecider(new MyHttpsTrustDecider(new String[] {
773: "Gordy", "Bethal" }));
774:
775: // Without preemptive user/pass Bethal returns a
776: // 401 for realm Cronus. If we supply any name other
777: // than Edward, George, or Mary, with the pass of "password"
778: // we should succeed.
779: http.setBasicAuthSupplier(new MyBasicAuthSupplier("Cronus",
780: "Betty", "password"));
781:
782: // We actually get our answer from Bethal at the end of the
783: // redirects.
784: String answer = gordy.sayHi();
785: assertTrue("Unexpected answer: " + answer,
786: "Bonjour from Bethal".equals(answer));
787:
788: // Uhe loop auth supplier,
789: // We should die with looping realms.
790: http.setBasicAuthSupplier(new MyBasicAuthSupplier());
791:
792: try {
793: answer = gordy.sayHi();
794: fail("Unexpected answer from Gordy: " + answer);
795: } catch (Exception e) {
796: //e.printStackTrace();
797: }
798: }
799:
800: }
|