Skip to content
This repository was archived by the owner on May 28, 2018. It is now read-only.

HttpAuthenticationFilter should choose the strongest authentication mechanism #3562

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,25 @@ public String getFilter(@Context HttpHeaders h) {
return "GET";
}

@GET
@Path("basicAndDigest")
public String getBasicAndDigest(@Context HttpHeaders h) {
String value = h.getRequestHeaders().getFirst("Authorization");
if (value == null) {
throw new WebApplicationException(
Response.status(401).header("WWW-Authenticate", "Basic realm=\"WallyWorld\"")
.header("WWW-Authenticate", "Digest realm=\"WallyWorld\"")
.entity("Forbidden").build());
} else if (value.startsWith("Basic")) {
throw new WebApplicationException(
Response.status(401).header("WWW-Authenticate", "Basic realm=\"WallyWorld\"")
.header("WWW-Authenticate", "Digest realm=\"WallyWorld\"")
.entity("Digest authentication expected").build());
}

return "GET";
}

@POST
public String post(@Context HttpHeaders h, String e) {
requestCount++;
Expand Down Expand Up @@ -259,6 +278,17 @@ public void testAuthGetWithClientFilter() {
assertEquals("GET", r.request().get(String.class));
}

@Test
public void testAuthGetWithBasicAndDigestFilter() {
ClientConfig cc = new ClientConfig();
cc.connectorProvider(new ApacheConnectorProvider());
Client client = ClientBuilder.newClient(cc);
client.register(HttpAuthenticationFeature.universal("name", "password"));
WebTarget r = client.target(getBaseUri()).path("test/basicAndDigest");

assertEquals("GET", r.request().get(String.class));
}

@Test
@Ignore("JERSEY-1750: Cannot retry request with a non-repeatable request entity. How to buffer the entity?"
+ " Allow repeatable write in jersey?")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,9 @@
import java.util.List;
import java.util.Map;

import javax.annotation.Priority;
import javax.ws.rs.Priorities;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.ClientRequestContext;
import javax.ws.rs.client.ClientRequestFilter;
import javax.ws.rs.client.ClientResponseContext;
Expand All @@ -66,8 +66,6 @@
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.Response;

import javax.annotation.Priority;

import org.glassfish.jersey.client.ClientProperties;
import org.glassfish.jersey.client.internal.LocalizationMessages;

Expand Down Expand Up @@ -222,15 +220,21 @@ public void filter(ClientRequestContext request, ClientResponseContext response)
Type result = null; // which authentication is requested: BASIC or DIGEST
boolean authenticate;

// If the server requests both BASIC and DIGEST, prefer DIGEST since it's stronger
// (see https://tools.ietf.org/html/rfc2617#section-4.6)
if (response.getStatus() == Response.Status.UNAUTHORIZED.getStatusCode()) {
String authString = response.getHeaders().getFirst(HttpHeaders.WWW_AUTHENTICATE);
if (authString != null) {
final String upperCaseAuth = authString.trim().toUpperCase();
if (upperCaseAuth.startsWith("BASIC")) {
result = Type.BASIC;
} else if (upperCaseAuth.startsWith("DIGEST")) {
result = Type.DIGEST;
} else {
List<String> authStrings = response.getHeaders().get(HttpHeaders.WWW_AUTHENTICATE);
if (authStrings != null) {
for (String authString : authStrings) {
final String upperCaseAuth = authString.trim().toUpperCase();
if (result == null && upperCaseAuth.startsWith("BASIC")) {
result = Type.BASIC;
} else if (upperCaseAuth.startsWith("DIGEST")) {
result = Type.DIGEST;
}
}

if (result == null) {
// unknown authentication -> this filter cannot authenticate with this method
return;
}
Expand Down