test/jdk/java/net/httpclient/DigestEchoClient.java
branchhttp-client-branch
changeset 56070 66a9c3185028
parent 56054 352e845ae744
child 56081 20c6742e5545
equal deleted inserted replaced
56069:ffaea9a1eed5 56070:66a9c3185028
    59 /**
    59 /**
    60  * @test
    60  * @test
    61  * @summary this test verifies that a client may provides authorization
    61  * @summary this test verifies that a client may provides authorization
    62  *          headers directly when connecting with a server.
    62  *          headers directly when connecting with a server.
    63  * @bug 8087112
    63  * @bug 8087112
    64  * @library /lib/testlibrary
    64  * @library /lib/testlibrary http2/server
    65  * @build jdk.testlibrary.SimpleSSLContext DigestEchoServer DigestEchoClient
    65  * @build jdk.testlibrary.SimpleSSLContext HttpServerAdapters DigestEchoServer DigestEchoClient
    66  * @modules jdk.incubator.httpclient
    66  * @modules jdk.incubator.httpclient/jdk.incubator.http.internal.common
       
    67  *          jdk.incubator.httpclient/jdk.incubator.http.internal.frame
       
    68  *          jdk.incubator.httpclient/jdk.incubator.http.internal.hpack
       
    69  *          java.logging
       
    70  *          java.base/sun.net.www.http
    67  *          java.base/sun.net.www
    71  *          java.base/sun.net.www
    68  *          java.base/sun.net
    72  *          java.base/sun.net
    69  * @run main/othervm DigestEchoClient
    73  * @run main/othervm DigestEchoClient
    70  * @run main/othervm -Djdk.http.auth.proxying.disabledSchemes=
    74  * @run main/othervm -Djdk.http.auth.proxying.disabledSchemes=
    71  *                   -Djdk.http.auth.tunneling.disabledSchemes=
    75  *                   -Djdk.http.auth.tunneling.disabledSchemes=
    92         final DigestEchoServer.HttpAuthType authType;
    96         final DigestEchoServer.HttpAuthType authType;
    93         final DigestEchoServer.HttpAuthSchemeType authScheme;
    97         final DigestEchoServer.HttpAuthSchemeType authScheme;
    94         final String protocolScheme;
    98         final String protocolScheme;
    95         final String key;
    99         final String key;
    96         final DigestEchoServer server;
   100         final DigestEchoServer server;
       
   101         final Version serverVersion;
    97 
   102 
    98         private EchoServers(DigestEchoServer server,
   103         private EchoServers(DigestEchoServer server,
       
   104                     Version version,
    99                     String protocolScheme,
   105                     String protocolScheme,
   100                     DigestEchoServer.HttpAuthType authType,
   106                     DigestEchoServer.HttpAuthType authType,
   101                     DigestEchoServer.HttpAuthSchemeType authScheme) {
   107                     DigestEchoServer.HttpAuthSchemeType authScheme) {
   102             this.authType = authType;
   108             this.authType = authType;
   103             this.authScheme = authScheme;
   109             this.authScheme = authScheme;
   104             this.protocolScheme = protocolScheme;
   110             this.protocolScheme = protocolScheme;
   105             this.key = key(protocolScheme, authType, authScheme);
   111             this.key = key(version, protocolScheme, authType, authScheme);
   106             this.server = server;
   112             this.server = server;
   107         }
   113             this.serverVersion = version;
   108 
   114         }
   109         static String key(String protocolScheme,
   115 
       
   116         static String key(Version version,
       
   117                           String protocolScheme,
   110                           DigestEchoServer.HttpAuthType authType,
   118                           DigestEchoServer.HttpAuthType authType,
   111                           DigestEchoServer.HttpAuthSchemeType authScheme) {
   119                           DigestEchoServer.HttpAuthSchemeType authScheme) {
   112             return String.format("%s:%s:%s", protocolScheme, authType, authScheme);
   120             return String.format("%s:%s:%s:%s", version, protocolScheme, authType, authScheme);
   113         }
   121         }
   114 
   122 
   115         private static EchoServers create(String protocolScheme,
   123         private static EchoServers create(Version version,
       
   124                                    String protocolScheme,
   116                                    DigestEchoServer.HttpAuthType authType,
   125                                    DigestEchoServer.HttpAuthType authType,
   117                                    DigestEchoServer.HttpAuthSchemeType authScheme) {
   126                                    DigestEchoServer.HttpAuthSchemeType authScheme) {
   118             try {
   127             try {
   119                 serverCount.incrementAndGet();
   128                 serverCount.incrementAndGet();
   120                 DigestEchoServer server =
   129                 DigestEchoServer server =
   121                     DigestEchoServer.create(protocolScheme, authType, authScheme);
   130                     DigestEchoServer.create(version, protocolScheme, authType, authScheme);
   122                 return new EchoServers(server, protocolScheme, authType, authScheme);
   131                 return new EchoServers(server, version, protocolScheme, authType, authScheme);
   123             } catch (IOException x) {
   132             } catch (IOException x) {
   124                 throw new UncheckedIOException(x);
   133                 throw new UncheckedIOException(x);
   125             }
   134             }
   126         }
   135         }
   127 
   136 
   128         public static DigestEchoServer of(String protocolScheme,
   137         public static DigestEchoServer of(Version version,
       
   138                                     String protocolScheme,
   129                                     DigestEchoServer.HttpAuthType authType,
   139                                     DigestEchoServer.HttpAuthType authType,
   130                                     DigestEchoServer.HttpAuthSchemeType authScheme) {
   140                                     DigestEchoServer.HttpAuthSchemeType authScheme) {
   131             String key = key(protocolScheme, authType, authScheme);
   141             String key = key(version, protocolScheme, authType, authScheme);
   132             return servers.computeIfAbsent(key, (k) ->
   142             return servers.computeIfAbsent(key, (k) ->
   133                     create(protocolScheme, authType, authScheme)).server;
   143                     create(version, protocolScheme, authType, authScheme)).server;
   134         }
   144         }
   135 
   145 
   136         public static void stop() {
   146         public static void stop() {
   137             for (EchoServers s : servers.values()) {
   147             for (EchoServers s : servers.values()) {
   138                 s.server.stop();
   148                 s.server.stop();
   212                 break;
   222                 break;
   213         }
   223         }
   214         return builder.build();
   224         return builder.build();
   215     }
   225     }
   216 
   226 
       
   227     public static List<Version> serverVersions(Version clientVersion) {
       
   228         if (clientVersion == Version.HTTP_1_1) {
       
   229             return List.of(clientVersion);
       
   230         } else {
       
   231             return List.of(Version.values());
       
   232         }
       
   233     }
       
   234 
       
   235     public static List<Version> clientVersions() {
       
   236         return List.of(Version.values());
       
   237     }
       
   238 
       
   239     public static List<Boolean> expectContinue(Version serverVersion) {
       
   240         if (serverVersion == Version.HTTP_1_1) {
       
   241             return BOOLEANS;
       
   242         } else {
       
   243             // our test HTTP/2 server does not support Expect: 100-Continue
       
   244             return List.of(Boolean.FALSE);
       
   245         }
       
   246     }
       
   247 
   217     public static void main(String[] args) throws Exception {
   248     public static void main(String[] args) throws Exception {
   218         boolean useSSL = false;
   249         boolean useSSL = false;
   219         EnumSet<DigestEchoServer.HttpAuthType> types =
   250         EnumSet<DigestEchoServer.HttpAuthType> types =
   220                 EnumSet.complementOf(EnumSet.of(DigestEchoServer.HttpAuthType.PROXY305));
   251                 EnumSet.complementOf(EnumSet.of(DigestEchoServer.HttpAuthType.PROXY305));
   221         if (args != null && args.length >= 1) {
   252         if (args != null && args.length >= 1) {
   237                                 DigestEchoServer.HttpAuthSchemeType.BASIC);
   268                                 DigestEchoServer.HttpAuthSchemeType.BASIC);
   238                 for (DigestEchoServer.HttpAuthSchemeType authScheme : basics) {
   269                 for (DigestEchoServer.HttpAuthSchemeType authScheme : basics) {
   239                     DigestEchoClient dec = new DigestEchoClient(useSSL,
   270                     DigestEchoClient dec = new DigestEchoClient(useSSL,
   240                             authScheme,
   271                             authScheme,
   241                             authType);
   272                             authType);
   242                     for (Version version : HttpClient.Version.values()) {
   273                     for (Version clientVersion : clientVersions()) {
   243                         for (boolean expectContinue : BOOLEANS) {
   274                         for (Version serverVersion : serverVersions(clientVersion)) {
   244                             for (boolean async : BOOLEANS) {
   275                             for (boolean expectContinue : expectContinue(serverVersion)) {
   245                                 for (boolean preemptive : BOOLEANS) {
   276                                 for (boolean async : BOOLEANS) {
   246                                     dec.testBasic(version, async,
   277                                     for (boolean preemptive : BOOLEANS) {
   247                                             expectContinue, preemptive);
   278                                         dec.testBasic(clientVersion,
       
   279                                                 serverVersion, async,
       
   280                                                 expectContinue, preemptive);
       
   281                                     }
   248                                 }
   282                                 }
   249                             }
   283                             }
   250                         }
   284                         }
   251                     }
   285                     }
   252                 }
   286                 }
   254                         EnumSet.of(DigestEchoServer.HttpAuthSchemeType.DIGEST);
   288                         EnumSet.of(DigestEchoServer.HttpAuthSchemeType.DIGEST);
   255                 for (DigestEchoServer.HttpAuthSchemeType authScheme : digests) {
   289                 for (DigestEchoServer.HttpAuthSchemeType authScheme : digests) {
   256                     DigestEchoClient dec = new DigestEchoClient(useSSL,
   290                     DigestEchoClient dec = new DigestEchoClient(useSSL,
   257                             authScheme,
   291                             authScheme,
   258                             authType);
   292                             authType);
   259                     for (Version version : HttpClient.Version.values()) {
   293                     for (Version clientVersion : clientVersions()) {
   260                         for (boolean expectContinue : BOOLEANS) {
   294                         for (Version serverVersion : serverVersions(clientVersion)) {
   261                             for (boolean async : BOOLEANS) {
   295                             for (boolean expectContinue : expectContinue(serverVersion)) {
   262                                 dec.testDigest(version, async, expectContinue);
   296                                 for (boolean async : BOOLEANS) {
       
   297                                     dec.testDigest(clientVersion, serverVersion,
       
   298                                             async, expectContinue);
       
   299                                 }
   263                             }
   300                             }
   264                         }
   301                         }
   265                     }
   302                     }
   266                 }
   303                 }
   267             }
   304             }
       
   305         } catch(Throwable t) {
       
   306             System.out.println("Unexpected exception: exiting: " + t);
       
   307             t.printStackTrace();
       
   308             throw t;
   268         } finally {
   309         } finally {
   269             EchoServers.stop();
   310             EchoServers.stop();
   270             System.out.println(" ---------------------------------------------------------- ");
   311             System.out.println(" ---------------------------------------------------------- ");
   271             System.out.println(String.format("DigestEchoClient %s %s", useSSL ? "SSL" : "CLEAR", types));
   312             System.out.println(String.format("DigestEchoClient %s %s", useSSL ? "SSL" : "CLEAR", types));
   272             System.out.println(String.format("Created %d clients and %d servers",
   313             System.out.println(String.format("Created %d clients and %d servers",
   314     }
   355     }
   315 
   356 
   316     final static AtomicLong basics = new AtomicLong();
   357     final static AtomicLong basics = new AtomicLong();
   317     final static AtomicLong basicCount = new AtomicLong();
   358     final static AtomicLong basicCount = new AtomicLong();
   318     // @Test
   359     // @Test
   319     void testBasic(HttpClient.Version version, boolean async,
   360     void testBasic(Version clientVersion, Version serverVersion, boolean async,
   320                    boolean expectContinue, boolean preemptive)
   361                    boolean expectContinue, boolean preemptive)
   321         throws Exception
   362         throws Exception
   322     {
   363     {
   323         final boolean addHeaders = authScheme == DigestEchoServer.HttpAuthSchemeType.BASICSERVER;
   364         final boolean addHeaders = authScheme == DigestEchoServer.HttpAuthSchemeType.BASICSERVER;
   324         // !preemptive has no meaning if we don't handle the authorization
   365         // !preemptive has no meaning if we don't handle the authorization
   325         // headers ourselves
   366         // headers ourselves
   326         if (!preemptive && !addHeaders) return;
   367         if (!preemptive && !addHeaders) return;
   327 
   368 
   328         out.println(format("*** testBasic: version: %s,  async: %s, useSSL: %s, " +
   369         out.println(format("*** testBasic: client: %s, server: %s, async: %s, useSSL: %s, " +
   329                         "authScheme: %s, authType: %s, expectContinue: %s preemptive: %s***",
   370                         "authScheme: %s, authType: %s, expectContinue: %s preemptive: %s***",
   330                 version, async, useSSL, authScheme, authType, expectContinue, preemptive));
   371                 clientVersion, serverVersion, async, useSSL, authScheme, authType,
   331 
   372                 expectContinue, preemptive));
   332         DigestEchoServer server = EchoServers.of(useSSL ? "https" : "http", authType, authScheme);
   373 
   333         URI uri = DigestEchoServer.uri(useSSL ? "https" : "http", server.getServerAddress(), "/foo/");
   374         DigestEchoServer server = EchoServers.of(serverVersion,
       
   375                 useSSL ? "https" : "http", authType, authScheme);
       
   376         URI uri = DigestEchoServer.uri(useSSL ? "https" : "http",
       
   377                 server.getServerAddress(), "/foo/");
   334 
   378 
   335         HttpClient client = newHttpClient(server);
   379         HttpClient client = newHttpClient(server);
   336         HttpResponse<String> r;
   380         HttpResponse<String> r;
   337         CompletableFuture<HttpResponse<String>> cf1;
   381         CompletableFuture<HttpResponse<String>> cf1;
   338         String auth = null;
   382         String auth = null;
   342                 out.println(DigestEchoServer.now() + " ----- iteration " + i + " -----");
   386                 out.println(DigestEchoServer.now() + " ----- iteration " + i + " -----");
   343                 List<String> lines = List.of(Arrays.copyOfRange(data, 0, i+1));
   387                 List<String> lines = List.of(Arrays.copyOfRange(data, 0, i+1));
   344                 assert lines.size() == i + 1;
   388                 assert lines.size() == i + 1;
   345                 String body = lines.stream().collect(Collectors.joining("\r\n"));
   389                 String body = lines.stream().collect(Collectors.joining("\r\n"));
   346                 HttpRequest.BodyPublisher reqBody = HttpRequest.BodyPublisher.fromString(body);
   390                 HttpRequest.BodyPublisher reqBody = HttpRequest.BodyPublisher.fromString(body);
   347                 HttpRequest.Builder builder = HttpRequest.newBuilder(uri).version(version)
   391                 HttpRequest.Builder builder = HttpRequest.newBuilder(uri).version(clientVersion)
   348                         .POST(reqBody).expectContinue(expectContinue);
   392                         .POST(reqBody).expectContinue(expectContinue);
   349                 boolean isTunnel = isProxy(authType) && useSSL;
   393                 boolean isTunnel = isProxy(authType) && useSSL;
   350                 if (addHeaders) {
   394                 if (addHeaders) {
   351                     // handle authentication ourselves
   395                     // handle authentication ourselves
   352                     assert !client.authenticator().isPresent();
   396                     assert !client.authenticator().isPresent();
   394                     throw new RuntimeException("Unexpected exception: " + t, t);
   438                     throw new RuntimeException("Unexpected exception: " + t, t);
   395                 }
   439                 }
   396 
   440 
   397                 if (addHeaders && !preemptive && (i==0 || isSchemeDisabled())) {
   441                 if (addHeaders && !preemptive && (i==0 || isSchemeDisabled())) {
   398                     assert resp.statusCode() == 401 || resp.statusCode() == 407;
   442                     assert resp.statusCode() == 401 || resp.statusCode() == 407;
   399                     request = HttpRequest.newBuilder(uri).version(version)
   443                     System.out.println(String.format("%s received: adding header %s: %s",
       
   444                             resp.statusCode(), authorizationKey(authType), auth));
       
   445                     request = HttpRequest.newBuilder(uri).version(clientVersion)
   400                             .POST(reqBody).header(authorizationKey(authType), auth).build();
   446                             .POST(reqBody).header(authorizationKey(authType), auth).build();
   401                     if (async) {
   447                     if (async) {
   402                         resp = client.sendAsync(request, asLines()).join();
   448                         resp = client.sendAsync(request, asLines()).join();
   403                     } else {
   449                     } else {
   404                         resp = client.send(request, asLines());
   450                         resp = client.send(request, asLines());
   417                         continue;
   463                         continue;
   418                     } else {
   464                     } else {
   419                         System.out.println("Scheme enabled for [" + authType
   465                         System.out.println("Scheme enabled for [" + authType
   420                                 + ", " + authScheme
   466                                 + ", " + authScheme
   421                                 + ", " + (useSSL ? "HTTPS" : "HTTP")
   467                                 + ", " + (useSSL ? "HTTPS" : "HTTP")
   422                                 + "]: Expecting 200");
   468                                 + "]: Expecting 200, response is: " + resp);
   423                         assert resp.statusCode() == 200;
   469                         assert resp.statusCode() == 200 : "200 expected, received " + resp;
   424                         respLines = resp.body().collect(Collectors.toList());
   470                         respLines = resp.body().collect(Collectors.toList());
   425                     }
   471                     }
   426                 } finally {
   472                 } finally {
   427                     long stop = System.nanoTime();
   473                     long stop = System.nanoTime();
   428                     synchronized (basicCount) {
   474                     synchronized (basicCount) {
   449     }
   495     }
   450 
   496 
   451     final static AtomicLong digests = new AtomicLong();
   497     final static AtomicLong digests = new AtomicLong();
   452     final static AtomicLong digestCount = new AtomicLong();
   498     final static AtomicLong digestCount = new AtomicLong();
   453     // @Test
   499     // @Test
   454     void testDigest(HttpClient.Version version, boolean async, boolean expectContinue)
   500     void testDigest(Version clientVersion, Version serverVersion,
       
   501                     boolean async, boolean expectContinue)
   455             throws Exception
   502             throws Exception
   456     {
   503     {
   457         out.println(format("*** testDigest: version: %s,  async: %s, useSSL: %s, " +
   504         out.println(format("*** testDigest: client: %s, server: %s, async: %s, useSSL: %s, " +
   458                         "authScheme: %s, authType: %s, expectContinue: %s  ***",
   505                         "authScheme: %s, authType: %s, expectContinue: %s  ***",
   459                 version, async, useSSL, authScheme, authType, expectContinue));
   506                 clientVersion, serverVersion, async, useSSL,
   460         DigestEchoServer server = EchoServers.of(useSSL ? "https" : "http", authType, authScheme);
   507                 authScheme, authType, expectContinue));
   461 
   508         DigestEchoServer server = EchoServers.of(serverVersion,
   462         URI uri = DigestEchoServer.uri(useSSL ? "https" : "http", server.getServerAddress(), "/foo/");
   509                 useSSL ? "https" : "http", authType, authScheme);
       
   510 
       
   511         URI uri = DigestEchoServer.uri(useSSL ? "https" : "http",
       
   512                 server.getServerAddress(), "/foo/");
   463 
   513 
   464         HttpClient client = newHttpClient(server);
   514         HttpClient client = newHttpClient(server);
   465         HttpResponse<String> r;
   515         HttpResponse<String> r;
   466         CompletableFuture<HttpResponse<String>> cf1;
   516         CompletableFuture<HttpResponse<String>> cf1;
   467         byte[] cnonce = new byte[16];
   517         byte[] cnonce = new byte[16];
   474                 List<String> lines = List.of(Arrays.copyOfRange(data, 0, i+1));
   524                 List<String> lines = List.of(Arrays.copyOfRange(data, 0, i+1));
   475                 assert lines.size() == i + 1;
   525                 assert lines.size() == i + 1;
   476                 String body = lines.stream().collect(Collectors.joining("\r\n"));
   526                 String body = lines.stream().collect(Collectors.joining("\r\n"));
   477                 HttpRequest.BodyPublisher reqBody = HttpRequest.BodyPublisher.fromString(body);
   527                 HttpRequest.BodyPublisher reqBody = HttpRequest.BodyPublisher.fromString(body);
   478                 HttpRequest.Builder reqBuilder = HttpRequest
   528                 HttpRequest.Builder reqBuilder = HttpRequest
   479                         .newBuilder(uri).version(version).POST(reqBody)
   529                         .newBuilder(uri).version(clientVersion).POST(reqBody)
   480                         .expectContinue(expectContinue);
   530                         .expectContinue(expectContinue);
   481 
   531 
   482                 boolean isTunnel = isProxy(authType) && useSSL;
   532                 boolean isTunnel = isProxy(authType) && useSSL;
   483                 String digestMethod = isTunnel ? "CONNECT" : "POST";
   533                 String digestMethod = isTunnel ? "CONNECT" : "POST";
   484 
   534 
   528                     }
   578                     }
   529                     challenge = DigestEchoServer.DigestResponse
   579                     challenge = DigestEchoServer.DigestResponse
   530                             .create(authenticate.substring("Digest ".length()));
   580                             .create(authenticate.substring("Digest ".length()));
   531                     String auth = digestResponse(uri, digestMethod, challenge, cnonceStr);
   581                     String auth = digestResponse(uri, digestMethod, challenge, cnonceStr);
   532                     try {
   582                     try {
   533                         request = HttpRequest.newBuilder(uri).version(version)
   583                         request = HttpRequest.newBuilder(uri).version(clientVersion)
   534                             .POST(reqBody).header(authorizationKey(authType), auth).build();
   584                             .POST(reqBody).header(authorizationKey(authType), auth).build();
   535                     } catch (IllegalArgumentException x) {
   585                     } catch (IllegalArgumentException x) {
   536                         throw x;
   586                         throw x;
   537                     }
   587                     }
   538 
   588 
   558                         assert resp.statusCode() == 200;
   608                         assert resp.statusCode() == 200;
   559                         respLines = resp.body().collect(Collectors.toList());
   609                         respLines = resp.body().collect(Collectors.toList());
   560                     }
   610                     }
   561                 } finally {
   611                 } finally {
   562                     long stop = System.nanoTime();
   612                     long stop = System.nanoTime();
   563                     synchronized (basicCount) {
   613                     synchronized (digestCount) {
   564                         long n = basicCount.getAndIncrement();
   614                         long n = digestCount.getAndIncrement();
   565                         basics.set((basics.get() * n + (stop - start)) / (n + 1));
   615                         digests.set((digests.get() * n + (stop - start)) / (n + 1));
   566                     }
   616                     }
   567                 }
   617                 }
   568                 if (!lines.equals(respLines)) {
   618                 if (!lines.equals(respLines)) {
   569                     throw new RuntimeException("Unexpected response: " + respLines);
   619                     throw new RuntimeException("Unexpected response: " + respLines);
   570                 }
   620                 }