Skip to content

Commit 5d05ef0

Browse files
committed
8372731: Detailed authentication failure messages
Backport-of: 895232fc65cab9ba3863b48cab27b688096a7435
1 parent 86e5f47 commit 5d05ef0

10 files changed

Lines changed: 276 additions & 85 deletions

File tree

src/java.base/share/classes/sun/net/www/protocol/http/AuthenticationInfo.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 1995, 2024, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 1995, 2025, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -25,6 +25,7 @@
2525

2626
package sun.net.www.protocol.http;
2727

28+
import java.io.IOException;
2829
import java.net.PasswordAuthentication;
2930
import java.net.URL;
3031
import java.util.HashMap;
@@ -428,9 +429,10 @@ public String getHeaderName() {
428429
* @param conn The connection to apply the header(s) to
429430
* @param p A source of header values for this connection, if needed.
430431
* @param raw The raw header field (if needed)
431-
* @return true if all goes well, false if no headers were set.
432+
* @throws IOException if no headers were set
432433
*/
433-
public abstract boolean setHeaders(HttpURLConnection conn, HeaderParser p, String raw);
434+
public abstract void setHeaders(HttpURLConnection conn, HeaderParser p, String raw)
435+
throws IOException;
434436

435437
/**
436438
* Check if the header indicates that the current auth. parameters are stale.

src/java.base/share/classes/sun/net/www/protocol/http/BasicAuthentication.java

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -125,15 +125,13 @@ public boolean supportsPreemptiveAuthorization() {
125125
* @param conn The connection to apply the header(s) to
126126
* @param p A source of header values for this connection, if needed.
127127
* @param raw The raw header values for this connection, if needed.
128-
* @return true if all goes well, false if no headers were set.
129128
*/
130129
@Override
131-
public boolean setHeaders(HttpURLConnection conn, HeaderParser p, String raw) {
130+
public void setHeaders(HttpURLConnection conn, HeaderParser p, String raw) {
132131
// no need to synchronize here:
133132
// already locked by s.n.w.p.h.HttpURLConnection
134133
assert conn.isLockHeldByCurrentThread();
135134
conn.setAuthenticationProperty(getHeaderName(), getHeaderValue(null,null));
136-
return true;
137135
}
138136

139137
/**

src/java.base/share/classes/sun/net/www/protocol/http/DigestAuthentication.java

Lines changed: 29 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -321,7 +321,11 @@ public boolean supportsPreemptiveAuthorization() {
321321
*/
322322
@Override
323323
public String getHeaderValue(URL url, String method) {
324-
return getHeaderValueImpl(url.getFile(), method);
324+
try {
325+
return getHeaderValueImpl(url.getFile(), method);
326+
} catch (IOException _) {
327+
return null;
328+
}
325329
}
326330

327331
/**
@@ -339,7 +343,11 @@ public String getHeaderValue(URL url, String method) {
339343
* @return the value of the HTTP header this authentication wants set
340344
*/
341345
String getHeaderValue(String requestURI, String method) {
342-
return getHeaderValueImpl(requestURI, method);
346+
try {
347+
return getHeaderValueImpl(requestURI, method);
348+
} catch (IOException _) {
349+
return null;
350+
}
343351
}
344352

345353
/**
@@ -369,25 +377,26 @@ public boolean isAuthorizationStale (String header) {
369377
* @param conn The connection to apply the header(s) to
370378
* @param p A source of header values for this connection, if needed.
371379
* @param raw Raw header values for this connection, if needed.
372-
* @return true if all goes well, false if no headers were set.
380+
* @throws IOException if no headers were set
373381
*/
374382
@Override
375-
public boolean setHeaders(HttpURLConnection conn, HeaderParser p, String raw) {
383+
public void setHeaders(HttpURLConnection conn, HeaderParser p, String raw)
384+
throws IOException {
376385
// no need to synchronize here:
377386
// already locked by s.n.w.p.h.HttpURLConnection
378387
assert conn.isLockHeldByCurrentThread();
379388

380389
params.setNonce (p.findValue("nonce"));
381390
params.setOpaque (p.findValue("opaque"));
382391
params.setQop (p.findValue("qop"));
383-
params.setUserhash (Boolean.valueOf(p.findValue("userhash")));
392+
params.setUserhash (Boolean.parseBoolean(p.findValue("userhash")));
384393
String charset = p.findValue("charset");
385394
if (charset == null) {
386395
charset = "ISO_8859_1";
387396
} else if (!charset.equalsIgnoreCase("UTF-8")) {
388397
// UTF-8 is only valid value. ISO_8859_1 represents default behavior
389398
// when the parameter is not set.
390-
return false;
399+
throw new IOException("Illegal charset in header");
391400
}
392401
params.setCharset(charset.toUpperCase(Locale.ROOT));
393402

@@ -405,7 +414,7 @@ public boolean setHeaders(HttpURLConnection conn, HeaderParser p, String raw) {
405414
}
406415

407416
if (params.nonce == null || authMethod == null || pw == null || realm == null) {
408-
return false;
417+
throw new IOException("Server challenge incomplete");
409418
}
410419
if (authMethod.length() >= 1) {
411420
// Method seems to get converted to all lower case elsewhere.
@@ -415,8 +424,7 @@ public boolean setHeaders(HttpURLConnection conn, HeaderParser p, String raw) {
415424
+ authMethod.substring(1).toLowerCase(Locale.ROOT);
416425
}
417426

418-
if (!setAlgorithmNames(p, params))
419-
return false;
427+
setAlgorithmNames(p, params);
420428

421429
// If authQop is true, then the server is doing RFC2617 and
422430
// has offered qop=auth. We do not support any other modes
@@ -426,20 +434,17 @@ public boolean setHeaders(HttpURLConnection conn, HeaderParser p, String raw) {
426434
params.setNewCnonce();
427435
}
428436

429-
String value = getHeaderValueImpl (uri, method);
430-
if (value != null) {
431-
conn.setAuthenticationProperty(getHeaderName(), value);
432-
return true;
433-
} else {
434-
return false;
435-
}
437+
String value = getHeaderValueImpl(uri, method);
438+
assert value != null;
439+
conn.setAuthenticationProperty(getHeaderName(), value);
436440
}
437441

438442
// Algorithm name is stored in two separate fields (of Paramaeters)
439443
// This allows for variations in digest algorithm name (aliases)
440444
// and also allow for the -sess variant defined in HTTP Digest protocol
441-
// returns false if algorithm not supported
442-
private static boolean setAlgorithmNames(HeaderParser p, Parameters params) {
445+
// throws IOException if algorithm not supported
446+
private static void setAlgorithmNames(HeaderParser p, Parameters params)
447+
throws IOException {
443448
String algorithm = p.findValue("algorithm");
444449
String digestName = algorithm;
445450
if (algorithm == null || algorithm.isEmpty()) {
@@ -459,18 +464,17 @@ private static boolean setAlgorithmNames(HeaderParser p, Parameters params) {
459464
var oid = KnownOIDs.findMatch(digestName);
460465
if (oid == null) {
461466
log("unknown algorithm: " + algorithm);
462-
return false;
467+
throw new IOException("Unknown algorithm: " + algorithm);
463468
}
464469
digestName = oid.stdName();
465470
params.setAlgorithm (algorithm);
466471
params.setDigestName (digestName);
467-
return true;
468472
}
469473

470474
/* Calculate the Authorization header field given the request URI
471475
* and based on the authorization information in params
472476
*/
473-
private String getHeaderValueImpl (String uri, String method) {
477+
private String getHeaderValueImpl (String uri, String method) throws IOException {
474478
String response;
475479
char[] passwd = pw.getPassword();
476480
boolean qop = params.authQop();
@@ -479,11 +483,7 @@ private String getHeaderValueImpl (String uri, String method) {
479483
String nonce = params.getNonce ();
480484
String algorithm = params.getAlgorithm ();
481485
String digest = params.getDigestName ();
482-
try {
483-
validateDigest(digest);
484-
} catch (IOException e) {
485-
return null;
486-
}
486+
validateDigest(digest);
487487
Charset charset = params.getCharset();
488488
boolean userhash = params.getUserhash ();
489489
params.incrementNC ();
@@ -505,7 +505,7 @@ private String getHeaderValueImpl (String uri, String method) {
505505
digest, session, charset);
506506
} catch (CharacterCodingException | NoSuchAlgorithmException ex) {
507507
log(ex.getMessage());
508-
return null;
508+
throw new IOException("Failed to compute digest", ex);
509509
}
510510

511511
String ncfield = "\"";
@@ -534,7 +534,7 @@ private String getHeaderValueImpl (String uri, String method) {
534534
}
535535
} catch (CharacterCodingException | NoSuchAlgorithmException ex) {
536536
log(ex.getMessage());
537-
return null;
537+
throw new IOException("Failed to compute user hash", ex);
538538
}
539539

540540
String value = authMethod

src/java.base/share/classes/sun/net/www/protocol/http/HttpURLConnection.java

Lines changed: 45 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@
6161
import java.util.StringJoiner;
6262
import jdk.internal.access.JavaNetHttpCookieAccess;
6363
import jdk.internal.access.SharedSecrets;
64+
import jdk.internal.util.Exceptions;
6465
import sun.net.NetProperties;
6566
import sun.net.NetworkClient;
6667
import sun.net.util.IPAddressUtil;
@@ -1464,16 +1465,29 @@ private InputStream getInputStream0() throws IOException {
14641465
/* in this case, only one header field will be present */
14651466
String raw = responses.findValue ("Proxy-Authenticate");
14661467
reset ();
1467-
if (!proxyAuthentication.setHeaders(this,
1468-
authhdr.headerParser(), raw)) {
1468+
try {
1469+
proxyAuthentication.setHeaders(this,
1470+
authhdr.headerParser(), raw);
1471+
} catch (IOException ex) {
14691472
disconnectInternal();
1470-
throw new IOException ("Authentication failure");
1473+
if (Exceptions.enhancedNonSocketExceptions()) {
1474+
throw new IOException ("Authentication failure", ex);
1475+
} else {
1476+
throw new IOException ("Authentication failure");
1477+
}
14711478
}
1472-
if (serverAuthentication != null && srvHdr != null &&
1473-
!serverAuthentication.setHeaders(this,
1474-
srvHdr.headerParser(), raw)) {
1475-
disconnectInternal ();
1476-
throw new IOException ("Authentication failure");
1479+
if (serverAuthentication != null && srvHdr != null) {
1480+
try {
1481+
serverAuthentication.setHeaders(this,
1482+
srvHdr.headerParser(), raw);
1483+
} catch (IOException ex) {
1484+
disconnectInternal();
1485+
if (Exceptions.enhancedNonSocketExceptions()) {
1486+
throw new IOException ("Authentication failure", ex);
1487+
} else {
1488+
throw new IOException ("Authentication failure");
1489+
}
1490+
}
14771491
}
14781492
authObj = null;
14791493
doingNTLMp2ndStage = false;
@@ -1552,9 +1566,15 @@ private InputStream getInputStream0() throws IOException {
15521566
} else {
15531567
reset ();
15541568
/* header not used for ntlm */
1555-
if (!serverAuthentication.setHeaders(this, null, raw)) {
1569+
try {
1570+
serverAuthentication.setHeaders(this, null, raw);
1571+
} catch (IOException ex) {
15561572
disconnectWeb();
1557-
throw new IOException ("Authentication failure");
1573+
if (Exceptions.enhancedNonSocketExceptions()) {
1574+
throw new IOException ("Authentication failure", ex);
1575+
} else {
1576+
throw new IOException ("Authentication failure");
1577+
}
15581578
}
15591579
doingNTLM2ndStage = false;
15601580
authObj = null;
@@ -1944,10 +1964,16 @@ private void doTunneling0() throws IOException {
19441964
} else {
19451965
String raw = responses.findValue ("Proxy-Authenticate");
19461966
reset ();
1947-
if (!proxyAuthentication.setHeaders(this,
1948-
authhdr.headerParser(), raw)) {
1967+
try {
1968+
proxyAuthentication.setHeaders(this,
1969+
authhdr.headerParser(), raw);
1970+
} catch (IOException ex) {
19491971
disconnectInternal();
1950-
throw new IOException ("Authentication failure");
1972+
if (Exceptions.enhancedNonSocketExceptions()) {
1973+
throw new IOException ("Authentication failure", ex);
1974+
} else {
1975+
throw new IOException ("Authentication failure");
1976+
}
19511977
}
19521978
authObj = null;
19531979
doingNTLMp2ndStage = false;
@@ -2210,7 +2236,9 @@ yield new DigestAuthentication(true, host, port, realm,
22102236
};
22112237
}
22122238
if (ret != null) {
2213-
if (!ret.setHeaders(this, p, raw)) {
2239+
try {
2240+
ret.setHeaders(this, p, raw);
2241+
} catch (IOException e) {
22142242
ret.disposeContext();
22152243
ret = null;
22162244
}
@@ -2367,7 +2395,9 @@ private AuthenticationInfo getServerAuthentication(AuthenticationHeader authhdr)
23672395
}
23682396
}
23692397
if (ret != null ) {
2370-
if (!ret.setHeaders(this, p, raw)) {
2398+
try {
2399+
ret.setHeaders(this, p, raw);
2400+
} catch (IOException e) {
23712401
ret.disposeContext();
23722402
ret = null;
23732403
}

src/java.base/share/classes/sun/net/www/protocol/http/NegotiateAuthentication.java

Lines changed: 12 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -168,29 +168,24 @@ public boolean isAuthorizationStale (String header) {
168168
* @param p A source of header values for this connection, not used because
169169
* HeaderParser converts the fields to lower case, use raw instead
170170
* @param raw The raw header field.
171-
* @return true if all goes well, false if no headers were set.
171+
* @throws IOException if no headers were set
172172
*/
173173
@Override
174-
public boolean setHeaders(HttpURLConnection conn, HeaderParser p, String raw) {
174+
public void setHeaders(HttpURLConnection conn, HeaderParser p, String raw) throws IOException {
175175
// no need to synchronize here:
176176
// already locked by s.n.w.p.h.HttpURLConnection
177177
assert conn.isLockHeldByCurrentThread();
178178

179-
try {
180-
String response;
181-
byte[] incoming = null;
182-
String[] parts = raw.split("\\s+");
183-
if (parts.length > 1) {
184-
incoming = Base64.getDecoder().decode(parts[1]);
185-
}
186-
response = hci.scheme + " " + Base64.getEncoder().encodeToString(
187-
incoming==null?firstToken():nextToken(incoming));
188-
189-
conn.setAuthenticationProperty(getHeaderName(), response);
190-
return true;
191-
} catch (IOException e) {
192-
return false;
179+
String response;
180+
byte[] incoming = null;
181+
String[] parts = raw.split("\\s+");
182+
if (parts.length > 1) {
183+
incoming = Base64.getDecoder().decode(parts[1]);
193184
}
185+
response = hci.scheme + " " + Base64.getEncoder().encodeToString(
186+
incoming==null?firstToken():nextToken(incoming));
187+
188+
conn.setAuthenticationProperty(getHeaderName(), response);
194189
}
195190

196191
/**

0 commit comments

Comments
 (0)