Skip to content
Merged
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 @@ -44,6 +44,7 @@
import org.apache.hc.client5.http.auth.AuthSchemeFactory;
import org.apache.hc.client5.http.auth.AuthScope;
import org.apache.hc.client5.http.auth.BearerToken;
import org.apache.hc.client5.http.auth.ChallengeType;
import org.apache.hc.client5.http.auth.CredentialsProvider;
import org.apache.hc.client5.http.auth.StandardAuthScheme;
import org.apache.hc.client5.http.auth.UsernamePasswordCredentials;
Expand Down Expand Up @@ -116,7 +117,7 @@ void testBasicAuthenticationNoCreds() throws Exception {
Assertions.assertNotNull(response);
Assertions.assertEquals(HttpStatus.SC_UNAUTHORIZED, response.getCode());
Mockito.verify(credsProvider).getCredentials(
Mockito.eq(new AuthScope(target, "test realm", "basic")), Mockito.any());
Mockito.eq(new AuthScope(target, "test realm", "basic", ChallengeType.TARGET)), Mockito.any());
}

@Test
Expand All @@ -141,7 +142,8 @@ void testBasicAuthenticationFailure() throws Exception {
Assertions.assertNotNull(response);
Assertions.assertEquals(HttpStatus.SC_UNAUTHORIZED, response.getCode());
Mockito.verify(credsProvider).getCredentials(
Mockito.eq(new AuthScope(target, "test realm", "basic")), Mockito.any());
Mockito.eq(new AuthScope(target, "test realm", "basic", ChallengeType.TARGET)),
Mockito.any());
}

@Test
Expand All @@ -167,7 +169,8 @@ void testBasicAuthenticationSuccess() throws Exception {
Assertions.assertNotNull(response);
Assertions.assertEquals(HttpStatus.SC_OK, response.getCode());
Mockito.verify(credsProvider).getCredentials(
Mockito.eq(new AuthScope(target, "test realm", "basic")), Mockito.any());
Mockito.eq(new AuthScope(target, "test realm", "basic", ChallengeType.TARGET)),
Mockito.any());
}

@Test
Expand All @@ -193,7 +196,8 @@ void testBasicAuthenticationWithEntitySuccess() throws Exception {
Assertions.assertNotNull(response);
Assertions.assertEquals(HttpStatus.SC_OK, response.getCode());
Mockito.verify(credsProvider).getCredentials(
Mockito.eq(new AuthScope(target, "test realm", "basic")), Mockito.any());
Mockito.eq(new AuthScope(target, "test realm", "basic", ChallengeType.TARGET)),
Mockito.any());
}

@Test
Expand Down Expand Up @@ -245,7 +249,8 @@ void testBasicAuthenticationExpectationSuccess() throws Exception {
Assertions.assertNotNull(response);
Assertions.assertEquals(HttpStatus.SC_OK, response.getCode());
Mockito.verify(credsProvider).getCredentials(
Mockito.eq(new AuthScope(target, "test realm", "basic")), Mockito.any());
Mockito.eq(new AuthScope(target, "test realm", "basic", ChallengeType.TARGET)),
Mockito.any());
}

@Test
Expand Down Expand Up @@ -453,7 +458,8 @@ protected void customizeUnauthorizedResponse(final HttpResponse unauthorized) {
Assertions.assertNotNull(response);
Assertions.assertEquals(HttpStatus.SC_OK, response.getCode());
Mockito.verify(credsProvider).getCredentials(
Mockito.eq(new AuthScope(target, "test realm", "basic")), Mockito.any());
Mockito.eq(new AuthScope(target, "test realm", "basic", ChallengeType.TARGET)),
Mockito.any());
}

private final static String CHARS = "0123456789abcdef";
Expand Down Expand Up @@ -491,7 +497,8 @@ void testBearerTokenAuthentication() throws Exception {
Assertions.assertNotNull(response1);
Assertions.assertEquals(HttpStatus.SC_UNAUTHORIZED, response1.getCode());
Mockito.verify(credsProvider).getCredentials(
Mockito.eq(new AuthScope(target, "test realm", "bearer")), Mockito.any());
Mockito.eq(new AuthScope(target, "test realm", "bearer", ChallengeType.TARGET)),
Mockito.any());

final HttpClientContext context2 = HttpClientContext.create();
Mockito.when(credsProvider.getCredentials(Mockito.any(), Mockito.any()))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
import org.apache.hc.client5.http.async.methods.SimpleHttpResponse;
import org.apache.hc.client5.http.async.methods.SimpleRequestBuilder;
import org.apache.hc.client5.http.auth.AuthScope;
import org.apache.hc.client5.http.auth.ChallengeType;
import org.apache.hc.client5.http.auth.CredentialsProvider;
import org.apache.hc.client5.http.auth.UsernamePasswordCredentials;
import org.apache.hc.client5.http.protocol.HttpClientContext;
Expand Down Expand Up @@ -87,7 +88,7 @@ protected void customizeUnauthorizedResponse(final HttpResponse unauthorized) {
Assertions.assertNotNull(response);
Assertions.assertEquals(HttpStatus.SC_OK, response.getCode());
Mockito.verify(credsProvider).getCredentials(
Mockito.eq(new AuthScope(target, "test realm", "basic")), Mockito.any());
Mockito.eq(new AuthScope(target, "test realm", "basic", ChallengeType.TARGET)), Mockito.any());
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
import org.apache.hc.client5.http.auth.AuthSchemeFactory;
import org.apache.hc.client5.http.auth.AuthScope;
import org.apache.hc.client5.http.auth.BearerToken;
import org.apache.hc.client5.http.auth.ChallengeType;
import org.apache.hc.client5.http.auth.CredentialsProvider;
import org.apache.hc.client5.http.auth.StandardAuthScheme;
import org.apache.hc.client5.http.auth.UsernamePasswordCredentials;
Expand Down Expand Up @@ -137,7 +138,8 @@ void testBasicAuthenticationNoCreds() throws Exception {
return null;
});
Mockito.verify(credsProvider).getCredentials(
Mockito.eq(new AuthScope(target, "test realm", "basic")), Mockito.any());
Mockito.eq(new AuthScope(target, "test realm", "basic", ChallengeType.TARGET)),
Mockito.any());
}

@Test
Expand All @@ -163,7 +165,8 @@ void testBasicAuthenticationFailure() throws Exception {
return null;
});
Mockito.verify(credsProvider).getCredentials(
Mockito.eq(new AuthScope(target, "test realm", "basic")), Mockito.any());
Mockito.eq(new AuthScope(target, "test realm", "basic", ChallengeType.TARGET)),
Mockito.any());
}

@Test
Expand All @@ -188,7 +191,8 @@ void testBasicAuthenticationSuccess() throws Exception {
return null;
});
Mockito.verify(credsProvider).getCredentials(
Mockito.eq(new AuthScope(target, "test realm", "basic")), Mockito.any());
Mockito.eq(new AuthScope(target, "test realm", "basic", ChallengeType.TARGET)),
Mockito.any());
}

@Test
Expand Down Expand Up @@ -278,7 +282,8 @@ void testBasicAuthenticationSuccessOnRepeatablePost() throws Exception {
return null;
});
Mockito.verify(credsProvider).getCredentials(
Mockito.eq(new AuthScope(target, "test realm", "basic")), Mockito.any());
Mockito.eq(new AuthScope(target, "test realm", "basic", ChallengeType.TARGET)),
Mockito.any());
}

@Test
Expand Down Expand Up @@ -754,7 +759,8 @@ protected void customizeUnauthorizedResponse(final ClassicHttpResponse unauthori
return null;
});
Mockito.verify(credsProvider).getCredentials(
Mockito.eq(new AuthScope(target, "test realm", "basic")), Mockito.any());
Mockito.eq(new AuthScope(target, "test realm", "basic", ChallengeType.TARGET)),
Mockito.any());
}

private final static String CHARS = "0123456789abcdef";
Expand Down Expand Up @@ -794,7 +800,8 @@ void testBearerTokenAuthentication() throws Exception {
return null;
});
Mockito.verify(credsProvider).getCredentials(
Mockito.eq(new AuthScope(target, "test realm", "bearer")), Mockito.any());
Mockito.eq(new AuthScope(target, "test realm", "bearer", ChallengeType.TARGET)),
Mockito.any());

final HttpClientContext context2 = HttpClientContext.create();
Mockito.when(credsProvider.getCredentials(Mockito.any(), Mockito.any()))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,32 @@ boolean isResponseReady(
CredentialsProvider credentialsProvider,
HttpContext context) throws AuthenticationException;

/**
* Determines whether or not an authorization response can be generated based on
* the actual authentication state. Generally the outcome of this method will depend
* upon availability of user credentials necessary to produce an authorization
* response.
*
* @param host The opposite endpoint
* @param challengeType the challenge type
* @param credentialsProvider The credentials to be used for authentication
* @param context HTTP context
* @throws AuthenticationException if authorization string cannot
* be generated due to an authentication failure
*
* @return {@code true} if an authorization response can be generated and
* the authentication handshake can proceed, {@code false} otherwise.
*
* @since 5.7
*/
default boolean isResponseReady(
final HttpHost host,
final ChallengeType challengeType,
final CredentialsProvider credentialsProvider,
final HttpContext context) throws AuthenticationException {
return isResponseReady(host, credentialsProvider, context);
}

/**
* Returns {@link Principal} whose credentials are used to generate
* an authentication response. Connection based schemes are required
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ public class AuthScope {
private final int port;
private final String realm;
private final String schemeName;
private final ChallengeType challengeType;

/**
* Defines auth scope with the given {@code protocol}, {@code host}, {@code port},
Expand All @@ -65,18 +66,38 @@ public class AuthScope {
* to any realm on the host.
* @param schemeName authentication scheme name. May be {@code null} if applies
* to any auth scheme supported by the host.
*
* @since 5.7
*/
public AuthScope(
final String protocol,
final String host,
final int port,
final String realm,
final String schemeName) {
final String schemeName,
final ChallengeType challengeType) {
this.protocol = protocol != null ? protocol.toLowerCase(Locale.ROOT) : null;
this.host = host != null ? host.toLowerCase(Locale.ROOT) : null;
this.port = port >= 0 ? port : -1;
this.realm = realm;
this.schemeName = schemeName != null ? schemeName.toUpperCase(Locale.ROOT) : null;
this.challengeType = challengeType;
}

public AuthScope(
final String protocol,
final String host,
final int port,
final String realm,
final String schemeName) {
this(protocol, host, port, realm, schemeName, null);
}

public AuthScope(
final HttpHost origin,
final String realm,
final String schemeName) {
this(origin, realm, schemeName, null);
}

/**
Expand All @@ -88,18 +109,20 @@ public AuthScope(
* @param schemeName authentication scheme name. May be {@code null} if applies
* to any auth scheme supported by the host.
*
* @since 4.2
* @since 5.7
*/
public AuthScope(
final HttpHost origin,
final String realm,
final String schemeName) {
final String schemeName,
final ChallengeType challengeType) {
Args.notNull(origin, "Host");
this.protocol = origin.getSchemeName().toLowerCase(Locale.ROOT);
this.host = origin.getHostName().toLowerCase(Locale.ROOT);
this.port = origin.getPort() >= 0 ? origin.getPort() : -1;
this.realm = realm;
this.schemeName = schemeName != null ? schemeName.toUpperCase(Locale.ROOT) : null;
this.challengeType = challengeType;
}

/**
Expand All @@ -122,7 +145,7 @@ public AuthScope(final HttpHost origin) {
* to any port of the host.
*/
public AuthScope(final String host, final int port) {
this(null, host, port, null, null);
this(null, host, port, null, null, null);
}

/**
Expand All @@ -136,6 +159,7 @@ public AuthScope(final AuthScope authScope) {
this.port = authScope.getPort();
this.realm = authScope.getRealm();
this.schemeName = authScope.getSchemeName();
this.challengeType = authScope.getChallengeType();
}

public String getProtocol() {
Expand All @@ -158,6 +182,13 @@ public String getSchemeName() {
return this.schemeName;
}

/**
* @since 5.7
*/
public ChallengeType getChallengeType() {
return challengeType;
}

/**
* Tests if the authentication scopes match.
*
Expand All @@ -167,36 +198,43 @@ public String getSchemeName() {
*/
public int match(final AuthScope that) {
int factor = 0;
if (Objects.equals(this.schemeName, that.schemeName)) {
if (Objects.equals(this.challengeType, that.challengeType)) {
factor += 1;
} else {
if (this.challengeType != null && that.challengeType != null) {
return -1;
}
}
if (Objects.equals(this.schemeName, that.schemeName)) {
factor += 2;
} else {
if (this.schemeName != null && that.schemeName != null) {
return -1;
}
}
if (Objects.equals(this.realm, that.realm)) {
factor += 2;
factor += 4;
} else {
if (this.realm != null && that.realm != null) {
return -1;
}
}
if (this.port == that.port) {
factor += 4;
factor += 8;
} else {
if (this.port != -1 && that.port != -1) {
return -1;
}
}
if (Objects.equals(this.protocol, that.protocol)) {
factor += 8;
factor += 16;
} else {
if (this.protocol != null && that.protocol != null) {
return -1;
}
}
if (Objects.equals(this.host, that.host)) {
factor += 16;
factor += 32;
} else {
if (this.host != null && that.host != null) {
return -1;
Expand All @@ -216,7 +254,8 @@ public boolean equals(final Object obj) {
&& Objects.equals(this.host, that.host)
&& this.port == that.port
&& Objects.equals(this.realm, that.realm)
&& Objects.equals(this.schemeName, that.schemeName);
&& Objects.equals(this.schemeName, that.schemeName)
&& Objects.equals(this.challengeType, that.challengeType);
}
return false;
}
Expand All @@ -229,6 +268,7 @@ public int hashCode() {
hash = LangUtils.hashCode(hash, this.port);
hash = LangUtils.hashCode(hash, this.realm);
hash = LangUtils.hashCode(hash, this.schemeName);
hash = LangUtils.hashCode(hash, this.challengeType);
return hash;
}

Expand Down Expand Up @@ -266,6 +306,12 @@ public String toString() {
} else {
buffer.append("<any port>");
}
buffer.append(' ');
if (this.challengeType != null) {
buffer.append(this.challengeType);
} else {
buffer.append("<any challenge type>");
}
return buffer.toString();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -352,7 +352,7 @@ public boolean handleResponse(
final String schemeName = authScheme.getName();
final AuthChallenge challenge = challengeMap.get(schemeName.toLowerCase(Locale.ROOT));
authScheme.processChallenge(host, challenged, challenge, clientContext);
if (authScheme.isResponseReady(host, credsProvider, clientContext)) {
if (authScheme.isResponseReady(host, challengeType, credsProvider, clientContext)) {
authOptions.add(authScheme);
}
} catch (final AuthenticationException | MalformedChallengeException ex) {
Expand Down
Loading
Loading