Skip to content

Commit 895232f

Browse files
committed
8372731: Detailed authentication failure messages
Reviewed-by: dfuchs, michaelm
1 parent 5141e1a commit 895232f

File tree

10 files changed

+276
-85
lines changed

10 files changed

+276
-85
lines changed

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;
@@ -1469,16 +1470,29 @@ private InputStream getInputStream0() throws IOException {
14691470
/* in this case, only one header field will be present */
14701471
String raw = responses.findValue ("Proxy-Authenticate");
14711472
reset ();
1472-
if (!proxyAuthentication.setHeaders(this,
1473-
authhdr.headerParser(), raw)) {
1473+
try {
1474+
proxyAuthentication.setHeaders(this,
1475+
authhdr.headerParser(), raw);
1476+
} catch (IOException ex) {
14741477
disconnectInternal();
1475-
throw new IOException ("Authentication failure");
1478+
if (Exceptions.enhancedNonSocketExceptions()) {
1479+
throw new IOException ("Authentication failure", ex);
1480+
} else {
1481+
throw new IOException ("Authentication failure");
1482+
}
14761483
}
1477-
if (serverAuthentication != null && srvHdr != null &&
1478-
!serverAuthentication.setHeaders(this,
1479-
srvHdr.headerParser(), raw)) {
1480-
disconnectInternal ();
1481-
throw new IOException ("Authentication failure");
1484+
if (serverAuthentication != null && srvHdr != null) {
1485+
try {
1486+
serverAuthentication.setHeaders(this,
1487+
srvHdr.headerParser(), raw);
1488+
} catch (IOException ex) {
1489+
disconnectInternal();
1490+
if (Exceptions.enhancedNonSocketExceptions()) {
1491+
throw new IOException ("Authentication failure", ex);
1492+
} else {
1493+
throw new IOException ("Authentication failure");
1494+
}
1495+
}
14821496
}
14831497
authObj = null;
14841498
doingNTLMp2ndStage = false;
@@ -1557,9 +1571,15 @@ private InputStream getInputStream0() throws IOException {
15571571
} else {
15581572
reset ();
15591573
/* header not used for ntlm */
1560-
if (!serverAuthentication.setHeaders(this, null, raw)) {
1574+
try {
1575+
serverAuthentication.setHeaders(this, null, raw);
1576+
} catch (IOException ex) {
15611577
disconnectWeb();
1562-
throw new IOException ("Authentication failure");
1578+
if (Exceptions.enhancedNonSocketExceptions()) {
1579+
throw new IOException ("Authentication failure", ex);
1580+
} else {
1581+
throw new IOException ("Authentication failure");
1582+
}
15631583
}
15641584
doingNTLM2ndStage = false;
15651585
authObj = null;
@@ -1935,10 +1955,16 @@ private void doTunneling0() throws IOException {
19351955
} else {
19361956
String raw = responses.findValue ("Proxy-Authenticate");
19371957
reset ();
1938-
if (!proxyAuthentication.setHeaders(this,
1939-
authhdr.headerParser(), raw)) {
1958+
try {
1959+
proxyAuthentication.setHeaders(this,
1960+
authhdr.headerParser(), raw);
1961+
} catch (IOException ex) {
19401962
disconnectInternal();
1941-
throw new IOException ("Authentication failure");
1963+
if (Exceptions.enhancedNonSocketExceptions()) {
1964+
throw new IOException ("Authentication failure", ex);
1965+
} else {
1966+
throw new IOException ("Authentication failure");
1967+
}
19421968
}
19431969
authObj = null;
19441970
doingNTLMp2ndStage = false;
@@ -2201,7 +2227,9 @@ yield new DigestAuthentication(true, host, port, realm,
22012227
};
22022228
}
22032229
if (ret != null) {
2204-
if (!ret.setHeaders(this, p, raw)) {
2230+
try {
2231+
ret.setHeaders(this, p, raw);
2232+
} catch (IOException e) {
22052233
ret.disposeContext();
22062234
ret = null;
22072235
}
@@ -2358,7 +2386,9 @@ private AuthenticationInfo getServerAuthentication(AuthenticationHeader authhdr)
23582386
}
23592387
}
23602388
if (ret != null ) {
2361-
if (!ret.setHeaders(this, p, raw)) {
2389+
try {
2390+
ret.setHeaders(this, p, raw);
2391+
} catch (IOException e) {
23622392
ret.disposeContext();
23632393
ret = null;
23642394
}

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)