49
49
import java .util .List ;
50
50
import java .util .Map ;
51
51
52
+ import javax .annotation .Priority ;
52
53
import javax .ws .rs .Priorities ;
53
54
import javax .ws .rs .client .Client ;
54
- import javax .ws .rs .client .ClientBuilder ;
55
55
import javax .ws .rs .client .ClientRequestContext ;
56
56
import javax .ws .rs .client .ClientRequestFilter ;
57
57
import javax .ws .rs .client .ClientResponseContext ;
66
66
import javax .ws .rs .core .MultivaluedMap ;
67
67
import javax .ws .rs .core .Response ;
68
68
69
- import javax .annotation .Priority ;
70
-
71
69
import org .glassfish .jersey .client .ClientProperties ;
72
70
import org .glassfish .jersey .client .internal .LocalizationMessages ;
73
71
@@ -222,16 +220,22 @@ public void filter(ClientRequestContext request, ClientResponseContext response)
222
220
Type result = null ; // which authentication is requested: BASIC or DIGEST
223
221
boolean authenticate ;
224
222
223
+ // If the server requests both BASIC and DIGEST, prefer DIGEST since it's stronger
224
+ // (see https://tools.ietf.org/html/rfc2617#section-4.6)
225
225
if (response .getStatus () == Response .Status .UNAUTHORIZED .getStatusCode ()) {
226
- String authString = response .getHeaders ().getFirst (HttpHeaders .WWW_AUTHENTICATE );
227
- if (authString != null ) {
228
- final String upperCaseAuth = authString .trim ().toUpperCase ();
229
- if (upperCaseAuth .startsWith ("BASIC" )) {
230
- result = Type .BASIC ;
231
- } else if (upperCaseAuth .startsWith ("DIGEST" )) {
232
- result = Type .DIGEST ;
233
- } else {
234
- // unknown authentication -> this filter cannot authenticate with this method
226
+ List <String > authStrings = response .getHeaders ().get (HttpHeaders .WWW_AUTHENTICATE );
227
+ if (authStrings != null ) {
228
+ for (String authString : authStrings ) {
229
+ final String upperCaseAuth = authString .trim ().toUpperCase ();
230
+ if (result == null && upperCaseAuth .startsWith ("BASIC" )) {
231
+ result = Type .BASIC ;
232
+ } else if (upperCaseAuth .startsWith ("DIGEST" )) {
233
+ result = Type .DIGEST ;
234
+ }
235
+ }
236
+
237
+ if (result == null ) {
238
+ // unknown authentication -> this filter cannot authenticate with this method
235
239
return ;
236
240
}
237
241
}
@@ -292,7 +296,7 @@ private void updateCache(ClientRequestContext request, boolean success, Type ope
292
296
* @param newAuthorizationHeader {@code Authorization} header that should be added to the new request.
293
297
* @return {@code true} is the authentication was successful ({@code true} if 401 response code was not returned;
294
298
* {@code false} otherwise).
295
- * @throws IOException
299
+ * @throws IOException
296
300
*/
297
301
static boolean repeatRequest (ClientRequestContext request , ClientResponseContext response , String newAuthorizationHeader )
298
302
throws IOException {
@@ -304,7 +308,7 @@ static boolean repeatRequest(ClientRequestContext request, ClientResponseContext
304
308
response .getEntityStream ().close ();
305
309
response .setEntityStream (null );
306
310
}
307
-
311
+
308
312
Client client = request .getClient ();
309
313
String method = request .getMethod ();
310
314
MediaType mediaType = request .getMediaType ();
@@ -328,6 +332,12 @@ static boolean repeatRequest(ClientRequestContext request, ClientResponseContext
328
332
329
333
builder .property (REQUEST_PROPERTY_FILTER_REUSED , "true" );
330
334
335
+ // Copy other properties, if any, from the original request
336
+ for (String propertyName : request .getPropertyNames ()) {
337
+ Object propertyValue = request .getProperty (propertyName );
338
+ builder .property (propertyName , propertyValue );
339
+ }
340
+
331
341
Invocation invocation ;
332
342
if (request .getEntity () == null ) {
333
343
invocation = builder .build (method );
0 commit comments