Path: blob/master/test/jdk/java/net/Authenticator/B4769350.java
41149 views
/*1* Copyright (c) 2002, 2019, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*/2223/**24* @test25* @bug 4769350 8017779 819116926* @modules jdk.httpserver27* @run main/othervm B4769350 server28* @run main/othervm B4769350 proxy29* @run main/othervm -Djava.net.preferIPv6Addresses=true B4769350 server30* @run main/othervm -Djava.net.preferIPv6Addresses=true B4769350 proxy31* @summary proxy authentication username and password caching only works in serial case32* Run in othervm since the test sets system properties that are read by the33* networking stack and cached when the HTTP handler is invoked, and previous34* tests may already have invoked the HTTP handler.35*/3637import com.sun.net.httpserver.HttpExchange;38import com.sun.net.httpserver.HttpHandler;39import com.sun.net.httpserver.HttpServer;40import java.io.*;41import java.net.*;42import java.util.concurrent.BrokenBarrierException;43import java.util.concurrent.CountDownLatch;44import java.util.concurrent.CyclicBarrier;45import java.util.concurrent.Executor;46import java.util.concurrent.ExecutorService;47import java.util.concurrent.Executors;4849public class B4769350 {5051static int count = 0;52static boolean error = false;5354static void read (InputStream is) throws IOException {55while (is.read() != -1) {56//System.out.write (c);57}58}5960static class Client extends Thread {61String authority, path;62boolean allowerror;6364Client (String authority, String path, boolean allowerror) {65super("Thread-" + path);66this.authority = authority;67this.path = path;68this.allowerror = allowerror;69}7071@Override72public void run () {73try {74URI u = new URI ("http", authority, path, null, null);75URL url = u.toURL();76URLConnection urlc = url.openConnection();77try (InputStream is = urlc.getInputStream()) {78read (is);79}80} catch (URISyntaxException e) {81System.out.println (e);82error = true;83} catch (IOException e) {84if (!allowerror) {85System.out.println (Thread.currentThread().getName()86+ " " + e);87e.printStackTrace();88error = true;89}90}91}92}9394class Server implements AutoCloseable {95HttpServer server;96Executor executor;9798public String getAddress() {99return server.getAddress().getHostName();100}101102public void startServer() {103InetAddress loopback = InetAddress.getLoopbackAddress();104InetSocketAddress addr = new InetSocketAddress(loopback, 0);105106try {107server = HttpServer.create(addr, 0);108} catch (IOException ioe) {109throw new RuntimeException("Server could not be created");110}111executor = Executors.newFixedThreadPool(10);112server.setExecutor(executor);113server.createContext("/test/realm1/t1a",114new AuthenticationHandlerT1a() );115server.createContext("/test/realm2/t1b",116new AuthenticationHandlerT1b());117server.createContext("/test/realm1/t1c",118new AuthenticationHandlerT1c());119server.createContext("/test/realm2/t1d",120new AuthenticationHandlerT1d());121server.createContext("/test/realm3/t2a",122new AuthenticationHandlerT2a());123server.createContext("/test/realm3/t2b",124new AuthenticationHandlerT2b());125server.createContext("/test/realm4/t3a",126new AuthenticationHandlerT3a());127server.createContext("/test/realm4/t3b",128new AuthenticationHandlerT3bc());129server.createContext("/test/realm4/t3c",130new AuthenticationHandlerT3bc());131t1Cond1 = new CyclicBarrier(3);132server.start();133}134135public int getPort() {136return server.getAddress().getPort();137}138139@Override140public void close() {141if (executor != null)142((ExecutorService)executor).shutdownNow();143if (server != null)144server.stop(0);145}146147/* T1 tests the client by sending 4 requests to 2 different realms148* in parallel. The client should recognise two pairs of dependent requests149* and execute the first of each pair in parallel. When they both succeed150* the second requests should be executed without calling the authenticator.151* The test succeeds if the authenticator was only called twice.152*/153class AuthenticationHandlerT1a implements HttpHandler154{155volatile int count = -1;156157@Override158public void handle(HttpExchange exchange) throws IOException {159count++;160try {161switch(count) {162case 0:163AuthenticationHandler.errorReply(exchange,164"Basic realm=\"realm1\"");165break;166case 1:167t1Cond1.await();168AuthenticationHandler.okReply(exchange);169break;170default:171System.out.println ("Unexpected request");172}173} catch (InterruptedException |174BrokenBarrierException e)175{176throw new RuntimeException(e);177}178}179}180181class AuthenticationHandlerT1b implements HttpHandler182{183volatile int count = -1;184185@Override186public void handle(HttpExchange exchange) throws IOException {187count++;188try {189switch(count) {190case 0:191AuthenticationHandler.errorReply(exchange,192"Basic realm=\"realm2\"");193break;194case 1:195t1Cond1.await();196AuthenticationHandler.okReply(exchange);197break;198default:199System.out.println ("Unexpected request");200}201} catch (InterruptedException | BrokenBarrierException e) {202throw new RuntimeException(e);203}204}205}206207class AuthenticationHandlerT1c implements HttpHandler208{209volatile int count = -1;210211@Override212public void handle(HttpExchange exchange) throws IOException {213count++;214switch(count) {215case 0:216AuthenticationHandler.errorReply(exchange,217"Basic realm=\"realm1\"");218break;219case 1:220AuthenticationHandler.okReply(exchange);221break;222default:223System.out.println ("Unexpected request");224}225}226}227228class AuthenticationHandlerT1d implements HttpHandler229{230volatile int count = -1;231232@Override233public void handle(HttpExchange exchange) throws IOException {234count++;235switch(count) {236case 0:237AuthenticationHandler.errorReply(exchange,238"Basic realm=\"realm2\"");239break;240case 1:241AuthenticationHandler.okReply(exchange);242break;243default:244System.out.println ("Unexpected request");245}246}247}248249/* T2 tests to check that if initial authentication fails, the second will250* succeed, and the authenticator is called twice251*/252253class AuthenticationHandlerT2a implements HttpHandler254{255volatile int count = -1;256257@Override258public void handle(HttpExchange exchange) throws IOException {259count++;260if (count == 1) {261t2condlatch.countDown();262}263AuthenticationHandler.errorReply(exchange,264"Basic realm=\"realm3\"");265266}267}268269class AuthenticationHandlerT2b implements HttpHandler270{271volatile int count = -1;272273@Override274public void handle(HttpExchange exchange) throws IOException {275count++;276switch(count) {277case 0:278AuthenticationHandler.errorReply(exchange,279"Basic realm=\"realm3\"");280break;281case 1:282AuthenticationHandler.okReply(exchange);283break;284default:285System.out.println ("Unexpected request");286}287}288}289290/* T3 tests proxy and server authentication. three threads request same291* resource at same time. Authenticator should be called once for server292* and once for proxy293*/294295class AuthenticationHandlerT3a implements HttpHandler296{297volatile int count = -1;298299@Override300public void handle(HttpExchange exchange) throws IOException {301count++;302switch(count) {303case 0:304AuthenticationHandler.proxyReply(exchange,305"Basic realm=\"proxy\"");306break;307case 1:308t3cond1.countDown();309AuthenticationHandler.errorReply(exchange,310"Basic realm=\"realm4\"");311break;312case 2:313AuthenticationHandler.okReply(exchange);314break;315default:316System.out.println ("Unexpected request");317}318}319}320321class AuthenticationHandlerT3bc implements HttpHandler322{323volatile int count = -1;324325@Override326public void handle(HttpExchange exchange) throws IOException {327count++;328switch(count) {329case 0:330AuthenticationHandler.proxyReply(exchange,331"Basic realm=\"proxy\"");332break;333case 1:334AuthenticationHandler.okReply(exchange);335break;336default:337System.out.println ("Unexpected request");338}339}340}341}342343static class AuthenticationHandler {344static void errorReply(HttpExchange exchange, String reply)345throws IOException346{347exchange.getResponseHeaders().add("Connection", "close");348exchange.getResponseHeaders().add("WWW-Authenticate", reply);349exchange.sendResponseHeaders(401, 0);350exchange.close();351}352353static void proxyReply (HttpExchange exchange, String reply)354throws IOException355{356exchange.getResponseHeaders().add("Proxy-Authenticate", reply);357exchange.sendResponseHeaders(407, 0);358}359360static void okReply (HttpExchange exchange) throws IOException {361exchange.getResponseHeaders().add("Connection", "close");362String response = "Hello .";363exchange.sendResponseHeaders(200, response.getBytes().length);364try (OutputStream os = exchange.getResponseBody()) {365os.write(response.getBytes());366}367exchange.close();368}369}370371static Server server;372static MyAuthenticator auth = new MyAuthenticator ();373374static int redirects = 4;375376static Client c1,c2,c3,c4,c5,c6,c7,c8,c9;377378static CountDownLatch t2condlatch;379static CountDownLatch t3cond1;380static CyclicBarrier t1Cond1;381382static void doServerTests (String authority, Server server) throws Exception383{384System.out.println ("Doing Server tests");385System.out.println ("T1");386c1 = new Client (authority, "/test/realm1/t1a", false);387c2 = new Client (authority, "/test/realm2/t1b", false);388c3 = new Client (authority, "/test/realm1/t1c", false);389c4 = new Client (authority, "/test/realm2/t1d", false);390c1.start(); c2.start();391t1Cond1.await();392c3.start(); c4.start();393c1.join(); c2.join(); c3.join(); c4.join();394395int f = auth.getCount();396if (f != 2) {397except ("Authenticator was called "+f+" times. Should be 2",398server);399}400if (error) {401except ("error occurred", server);402}403404auth.resetCount();405System.out.println ("T2");406407c5 = new Client (authority, "/test/realm3/t2a", true);408c6 = new Client (authority, "/test/realm3/t2b", false);409t2condlatch = new CountDownLatch(1);410c5.start ();411t2condlatch.await();412c6.start ();413c5.join(); c6.join();414415f = auth.getCount();416if (f != redirects+1) {417except ("Authenticator was called "+f+" times. Should be: "418+ redirects+1, server);419}420if (error) {421except ("error occurred", server);422}423}424425static void doProxyTests (String authority, Server server) throws Exception426{427System.out.println ("Doing Proxy tests");428c7 = new Client (authority, "/test/realm4/t3a", false);429c8 = new Client (authority, "/test/realm4/t3b", false);430c9 = new Client (authority, "/test/realm4/t3c", false);431t3cond1 = new CountDownLatch(1);432c7.start ();433t3cond1.await();434c8.start ();435c9.start ();436c7.join(); c8.join(); c9.join();437438int f = auth.getCount();439if (f != 2) {440except ("Authenticator was called "+f+" times. Should be: " + 2,441server);442}443if (error) {444except ("error occurred", server);445}446}447448public static void main (String[] args) throws Exception {449new B4769350().runTest(args[0].equals ("proxy"));450}451452public void runTest(boolean proxy) throws Exception {453System.setProperty ("http.maxRedirects", Integer.toString (redirects));454System.setProperty ("http.auth.serializeRequests", "true");455Authenticator.setDefault (auth);456try (Server server = new Server()) {457server.startServer();458System.out.println ("Server: listening on port: "459+ server.getPort());460if (proxy) {461System.setProperty ("http.proxyHost",462InetAddress.getLoopbackAddress().getHostAddress());463System.setProperty ("http.proxyPort",464Integer.toString(server.getPort()));465doProxyTests ("www.foo.com", server);466} else {467ProxySelector.setDefault(ProxySelector.of(null));468doServerTests (authority(server.getPort()), server);469}470}471472}473474static String authority(int port) {475InetAddress loopback = InetAddress.getLoopbackAddress();476String hoststr = loopback.getHostAddress();477if (hoststr.indexOf(':') > -1) {478hoststr = "[" + hoststr + "]";479}480return hoststr + ":" + port;481}482483public static void except (String s, Server server) {484server.close();485throw new RuntimeException (s);486}487488static class MyAuthenticator extends Authenticator {489MyAuthenticator () {490super ();491}492493volatile int count = 0;494495@Override496public PasswordAuthentication getPasswordAuthentication () {497PasswordAuthentication pw;498pw = new PasswordAuthentication ("user", "pass1".toCharArray());499count ++;500return pw;501}502503public void resetCount () {504count = 0;505}506507public int getCount () {508return count;509}510}511}512513514