RFC 7231: redesign of HTTP authenticator and related classes

git-svn-id: https://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk@1689155 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Oleg Kalnichevski 2015-07-04 13:42:40 +00:00
parent 11612ab974
commit 2f66271de9
35 changed files with 905 additions and 1642 deletions

View File

@ -29,13 +29,16 @@ package org.apache.http.client.fluent;
import java.io.IOException;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.util.Collections;
import java.util.concurrent.TimeUnit;
import javax.net.ssl.SSLContext;
import org.apache.http.HttpHost;
import org.apache.http.auth.AUTH;
import org.apache.http.NameValuePair;
import org.apache.http.auth.AuthChallenge;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.ChallengeType;
import org.apache.http.auth.Credentials;
import org.apache.http.auth.MalformedChallengeException;
import org.apache.http.auth.NTCredentials;
@ -58,7 +61,6 @@ import org.apache.http.impl.client.BasicAuthCache;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicHeader;
/**
* An Executor for fluent requests.
@ -151,7 +153,7 @@ public class Executor {
public Executor authPreemptive(final HttpHost host) {
final BasicScheme basicScheme = new BasicScheme();
try {
basicScheme.processChallenge(new BasicHeader(AUTH.WWW_AUTH, "BASIC "));
basicScheme.processChallenge(ChallengeType.TARGET, new AuthChallenge("basic", null, Collections.<NameValuePair>emptyList()));
} catch (final MalformedChallengeException ignore) {
}
this.authCache.put(host, basicScheme);
@ -168,7 +170,7 @@ public class Executor {
public Executor authPreemptiveProxy(final HttpHost proxy) {
final BasicScheme basicScheme = new BasicScheme();
try {
basicScheme.processChallenge(new BasicHeader(AUTH.PROXY_AUTH, "BASIC "));
basicScheme.processChallenge(ChallengeType.PROXY, new AuthChallenge("basic", null, Collections.<NameValuePair>emptyList()));
} catch (final MalformedChallengeException ignore) {
}
this.authCache.put(proxy, basicScheme);

View File

@ -34,14 +34,16 @@ import org.apache.http.HttpHost;
import org.apache.http.HttpRequest;
import org.apache.http.annotation.NotThreadSafe;
import org.apache.http.auth.AUTH;
import org.apache.http.auth.AuthChallenge;
import org.apache.http.auth.AuthenticationException;
import org.apache.http.auth.ChallengeType;
import org.apache.http.auth.Credentials;
import org.apache.http.auth.InvalidCredentialsException;
import org.apache.http.auth.MalformedChallengeException;
import org.apache.http.client.config.AuthSchemes;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.conn.routing.RouteInfo;
import org.apache.http.impl.auth.AuthSchemeBase;
import org.apache.http.impl.auth.NonStandardAuthScheme;
import org.apache.http.message.BufferedHeader;
import org.apache.http.protocol.HttpContext;
import org.apache.http.util.CharArrayBuffer;
@ -68,7 +70,7 @@ import com.sun.jna.ptr.IntByReference;
* @since 4.4
*/
@NotThreadSafe
public class WindowsNegotiateScheme extends AuthSchemeBase {
public class WindowsNegotiateScheme extends NonStandardAuthScheme {
private final Log log = LogFactory.getLog(getClass());
@ -79,13 +81,11 @@ public class WindowsNegotiateScheme extends AuthSchemeBase {
private CredHandle clientCred;
private CtxtHandle sspiContext;
private boolean continueNeeded;
private String challenge;
public WindowsNegotiateScheme(final String scheme, final String servicePrincipalName) {
super();
this.scheme = (scheme == null) ? AuthSchemes.SPNEGO : scheme;
this.challenge = null;
this.continueNeeded = true;
this.servicePrincipalName = servicePrincipalName;
@ -123,35 +123,21 @@ public class WindowsNegotiateScheme extends AuthSchemeBase {
return scheme;
}
// String parameters not supported
@Override
public String getParameter(final String name) {
return null;
}
// NTLM/Negotiate do not support authentication realms
@Override
public String getRealm() {
return null;
}
@Override
public boolean isConnectionBased() {
return true;
}
@Override
protected void parseChallenge(
final CharArrayBuffer buffer,
final int beginIndex,
final int endIndex) throws MalformedChallengeException {
this.challenge = buffer.substringTrimmed(beginIndex, endIndex);
if (this.challenge.isEmpty()) {
public void processChallenge(
final ChallengeType challengeType, final AuthChallenge authChallenge) throws MalformedChallengeException {
update(challengeType, authChallenge);
final String challenge = getChallenge();
if (challenge.isEmpty()) {
if (clientCred != null) {
dispose(); // run cleanup first before throwing an exception otherwise can leak OS resources
if (continueNeeded) {
throw new RuntimeException("Unexpected token");
throw new IllegalStateException("Unexpected token");
}
}
}
@ -163,6 +149,7 @@ public class WindowsNegotiateScheme extends AuthSchemeBase {
final HttpRequest request,
final HttpContext context) throws AuthenticationException {
final String challenge = getChallenge();
final String response;
if (clientCred == null) {
// ?? We don't use the credentials, should we allow anything?
@ -196,12 +183,12 @@ public class WindowsNegotiateScheme extends AuthSchemeBase {
throw ex;
}
}
} else if (this.challenge == null || this.challenge.isEmpty()) {
} else if (challenge == null || challenge.isEmpty()) {
failAuthCleanup();
throw new AuthenticationException("Authentication Failed");
} else {
try {
final byte[] continueTokenBytes = Base64.decodeBase64(this.challenge);
final byte[] continueTokenBytes = Base64.decodeBase64(challenge);
final SecBufferDesc continueTokenBuffer = new SecBufferDesc(
Sspi.SECBUFFER_TOKEN, continueTokenBytes);
final String targetName = getServicePrincipalName(context);

View File

@ -27,6 +27,7 @@
package org.apache.http.auth;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
@ -55,6 +56,10 @@ public final class AuthChallenge {
this.params = params != null ? Collections.unmodifiableList(new ArrayList<>(params)) : null;
}
public AuthChallenge(final String scheme, final NameValuePair... params) {
this(scheme, null, Arrays.asList(params));
}
public String getScheme() {
return scheme;
}

View File

@ -60,9 +60,32 @@ public interface AuthScheme {
* may involve multiple challenge-response exchanges. Such schemes must be able
* to maintain the state information when dealing with sequential challenges
*
* @param header the challenge header
* @param challengeType the challenge type
* @param authChallenge the auth challenge
*
* @since 5.0
*/
void processChallenge(final Header header) throws MalformedChallengeException;
void processChallenge(
ChallengeType challengeType,
AuthChallenge authChallenge) throws MalformedChallengeException;
/**
* Produces an authorization string for the given set of {@link Credentials}.
*
* @param credentials The credentials to be used for authentication
* @param request The request being authenticated
* @param context HTTP context
* @throws AuthenticationException if authorization string cannot
* be generated due to an authentication failure
*
* @return authorization header
*
* @since 5.0
*/
Header authenticate(
Credentials credentials,
HttpRequest request,
HttpContext context) throws AuthenticationException;
/**
* Returns textual designation of the given authentication scheme.
@ -109,23 +132,4 @@ public interface AuthScheme {
*/
boolean isComplete();
/**
* Produces an authorization string for the given set of
* {@link Credentials}.
*
* @param credentials The set of credentials to be used for athentication
* @param request The request being authenticated
* @param context HTTP context
* @throws AuthenticationException if authorization string cannot
* be generated due to an authentication failure
*
* @return the authorization string
*
* @since 5.0
*/
Header authenticate(
Credentials credentials,
HttpRequest request,
HttpContext context) throws AuthenticationException;
}

View File

@ -27,11 +27,11 @@
package org.apache.http.auth;
/**
* Challenge mode (TARGET or PROXY)
* Challenge type (TARGET or PROXY)
*
* @since 4.2
*/
public enum ChallengeState {
public enum ChallengeType {
TARGET, PROXY

View File

@ -30,18 +30,16 @@ package org.apache.http.client;
import java.util.Map;
import java.util.Queue;
import org.apache.http.Header;
import org.apache.http.HttpHost;
import org.apache.http.HttpResponse;
import org.apache.http.auth.AuthChallenge;
import org.apache.http.auth.AuthOption;
import org.apache.http.auth.AuthScheme;
import org.apache.http.auth.ChallengeType;
import org.apache.http.auth.MalformedChallengeException;
import org.apache.http.protocol.HttpContext;
/**
/**
* A handler for determining if an HTTP response represents an authentication challenge that was
* sent back to the client as a result of authentication failure.
* Strategy to select auth schemes in order of preference based on auth challenges
* presented by the opposite endpoint (target server or a proxy).
* <p>
* Implementations of this interface must be thread-safe. Access to shared data must be
* synchronized as methods of this interface may be executed from multiple threads.
@ -50,81 +48,25 @@ import org.apache.http.protocol.HttpContext;
*/
public interface AuthenticationStrategy {
/**
* Determines if the given HTTP response response represents
* an authentication challenge that was sent back as a result
* of authentication failure.
*
* @param authhost authentication host.
* @param response HTTP response.
* @param context HTTP context.
* @return {@code true} if user authentication is required,
* {@code false} otherwise.
*/
boolean isAuthenticationRequested(
HttpHost authhost,
HttpResponse response,
HttpContext context);
/**
* Extracts from the given HTTP response a collection of authentication
* challenges, each of which represents an authentication scheme supported
* by the authentication host.
*
* @param authhost authentication host.
* @param response HTTP response.
* @param context HTTP context.
* @return a collection of challenges keyed by names of corresponding
* authentication schemes.
* @throws MalformedChallengeException if one of the authentication
* challenges is not valid or malformed.
*/
Map<String, Header> getChallenges(
HttpHost authhost,
HttpResponse response,
HttpContext context) throws MalformedChallengeException;
/**
* Selects one authentication challenge out of all available and
* creates and generates {@link AuthOption} instance capable of
* processing that challenge.
*
* @param challengeType challenge type.
* @param host authentication host.
* @param challenges collection of challenges.
* @param authhost authentication host.
* @param response HTTP response.
* @param context HTTP context.
* @return authentication auth schemes that can be used for authentication. Can be empty.
* @throws MalformedChallengeException if one of the authentication
* challenges is not valid or malformed.
*
* @since 5.0
*/
Queue<AuthOption> select(
Map<String, Header> challenges,
HttpHost authhost,
HttpResponse response,
ChallengeType challengeType,
HttpHost host,
Map<String, AuthChallenge> challenges,
HttpContext context) throws MalformedChallengeException;
/**
* Callback invoked in case of successful authentication.
*
* @param authhost authentication host.
* @param authScheme authentication scheme used.
* @param context HTTP context.
*/
void authSucceeded(
HttpHost authhost,
AuthScheme authScheme,
HttpContext context);
/**
* Callback invoked in case of unsuccessful authentication.
*
* @param authhost authentication host.
* @param authScheme authentication scheme used.
* @param context HTTP context.
*/
void authFailed(
HttpHost authhost,
AuthScheme authScheme,
HttpContext context);
}

View File

@ -41,6 +41,8 @@ import org.apache.http.util.CharArrayBuffer;
public class AuthChallengeParser {
public static final AuthChallengeParser INSTANCE = new AuthChallengeParser();
private final TokenParser tokenParser = TokenParser.INSTANCE;
private final static char BLANK = ' ';
@ -60,7 +62,7 @@ public class AuthChallengeParser {
if (buffer.charAt(cursor.getPos()) == BLANK) {
tokenParser.skipWhiteSpace(buffer, cursor);
}
if (buffer.charAt(cursor.getPos()) == EQUAL_CHAR) {
if (!cursor.atEnd() && buffer.charAt(cursor.getPos()) == EQUAL_CHAR) {
cursor.updatePos(cursor.getPos() + 1);
final String value = tokenParser.parseValue(buffer, cursor, DELIMITER);
return new BasicNameValuePair(token, value);

View File

@ -1,143 +0,0 @@
/*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
*/
package org.apache.http.impl.auth;
import java.util.Locale;
import org.apache.http.FormattedHeader;
import org.apache.http.Header;
import org.apache.http.annotation.NotThreadSafe;
import org.apache.http.auth.AUTH;
import org.apache.http.auth.AuthScheme;
import org.apache.http.auth.ChallengeState;
import org.apache.http.auth.MalformedChallengeException;
import org.apache.http.protocol.HTTP;
import org.apache.http.util.Args;
import org.apache.http.util.CharArrayBuffer;
/**
* Abstract authentication scheme class that serves as a basis
* for all authentication schemes supported by HttpClient. This class
* defines the generic way of parsing an authentication challenge. It
* does not make any assumptions regarding the format of the challenge
* nor does it impose any specific way of responding to that challenge.
*
*
* @since 4.0
*/
@NotThreadSafe
public abstract class AuthSchemeBase implements AuthScheme {
protected ChallengeState challengeState;
public AuthSchemeBase() {
super();
}
/**
* Processes the given challenge token. Some authentication schemes
* may involve multiple challenge-response exchanges. Such schemes must be able
* to maintain the state information when dealing with sequential challenges
*
* @param header the challenge header
*
* @throws MalformedChallengeException is thrown if the authentication challenge
* is malformed
*/
@Override
public void processChallenge(final Header header) throws MalformedChallengeException {
Args.notNull(header, "Header");
final String authheader = header.getName();
if (authheader.equalsIgnoreCase(AUTH.WWW_AUTH)) {
this.challengeState = ChallengeState.TARGET;
} else if (authheader.equalsIgnoreCase(AUTH.PROXY_AUTH)) {
this.challengeState = ChallengeState.PROXY;
} else {
throw new MalformedChallengeException("Unexpected header name: " + authheader);
}
final CharArrayBuffer buffer;
int pos;
if (header instanceof FormattedHeader) {
buffer = ((FormattedHeader) header).getBuffer();
pos = ((FormattedHeader) header).getValuePos();
} else {
final String s = header.getValue();
if (s == null) {
throw new MalformedChallengeException("Header value is null");
}
buffer = new CharArrayBuffer(s.length());
buffer.append(s);
pos = 0;
}
while (pos < buffer.length() && HTTP.isWhitespace(buffer.charAt(pos))) {
pos++;
}
final int beginIndex = pos;
while (pos < buffer.length() && !HTTP.isWhitespace(buffer.charAt(pos))) {
pos++;
}
final int endIndex = pos;
final String s = buffer.substring(beginIndex, endIndex);
if (!s.equalsIgnoreCase(getSchemeName())) {
throw new MalformedChallengeException("Invalid scheme identifier: " + s);
}
parseChallenge(buffer, pos, buffer.length());
}
protected abstract void parseChallenge(
CharArrayBuffer buffer, int beginIndex, int endIndex) throws MalformedChallengeException;
/**
* Returns {@code true} if authenticating against a proxy, {@code false}
* otherwise.
*/
public boolean isProxy() {
return this.challengeState != null && this.challengeState == ChallengeState.PROXY;
}
/**
* Returns {@link ChallengeState} value or {@code null} if unchallenged.
*
* @since 4.2
*/
public ChallengeState getChallengeState() {
return this.challengeState;
}
@Override
public String toString() {
final String name = getSchemeName();
if (name != null) {
return name.toUpperCase(Locale.ROOT);
} else {
return super.toString();
}
}
}

View File

@ -26,6 +26,10 @@
*/
package org.apache.http.impl.auth;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.ObjectStreamException;
import java.nio.charset.Charset;
import org.apache.commons.codec.binary.Base64;
@ -34,13 +38,16 @@ import org.apache.http.Header;
import org.apache.http.HttpRequest;
import org.apache.http.annotation.NotThreadSafe;
import org.apache.http.auth.AUTH;
import org.apache.http.auth.AuthChallenge;
import org.apache.http.auth.AuthenticationException;
import org.apache.http.auth.ChallengeType;
import org.apache.http.auth.Credentials;
import org.apache.http.auth.MalformedChallengeException;
import org.apache.http.message.BufferedHeader;
import org.apache.http.protocol.HttpContext;
import org.apache.http.util.Args;
import org.apache.http.util.CharArrayBuffer;
import org.apache.http.util.CharsetUtils;
import org.apache.http.util.EncodingUtils;
/**
@ -49,18 +56,18 @@ import org.apache.http.util.EncodingUtils;
* @since 4.0
*/
@NotThreadSafe
public class BasicScheme extends RFC2617Scheme {
public class BasicScheme extends StandardAuthScheme {
private static final long serialVersionUID = -1931571557597830536L;
/** Whether the basic authentication process is complete */
private transient Charset charset;
private boolean complete;
/**
* @since 4.3
*/
public BasicScheme(final Charset credentialsCharset) {
super(credentialsCharset);
public BasicScheme(final Charset charset) {
this.charset = charset != null ? charset : Consts.ASCII;
this.complete = false;
}
@ -68,64 +75,28 @@ public class BasicScheme extends RFC2617Scheme {
this(Consts.ASCII);
}
/**
* Returns textual designation of the basic authentication scheme.
*
* @return {@code basic}
*/
@Override
public String getSchemeName() {
return "basic";
}
/**
* Processes the Basic challenge.
*
* @param header the challenge header
*
* @throws MalformedChallengeException is thrown if the authentication challenge
* is malformed
*/
@Override
public void processChallenge(
final Header header) throws MalformedChallengeException {
super.processChallenge(header);
final ChallengeType challengeType,
final AuthChallenge authChallenge) throws MalformedChallengeException {
update(challengeType, authChallenge);
this.complete = true;
}
/**
* Tests if the Basic authentication process has been completed.
*
* @return {@code true} if Basic authorization has been processed,
* {@code false} otherwise.
*/
@Override
public boolean isComplete() {
return this.complete;
}
/**
* Returns {@code false}. Basic authentication scheme is request based.
*
* @return {@code false}.
*/
@Override
public boolean isConnectionBased() {
return false;
}
/**
* Produces basic authorization header for the given set of {@link Credentials}.
*
* @param credentials The set of credentials to be used for authentication
* @param request The request being authenticated
* @throws org.apache.http.auth.InvalidCredentialsException if authentication
* credentials are not valid or not applicable for this authentication scheme
* @throws AuthenticationException if authorization string cannot
* be generated due to an authentication failure
*
* @return a basic authorization string
*/
@Override
public Header authenticate(
final Credentials credentials,
@ -134,15 +105,6 @@ public class BasicScheme extends RFC2617Scheme {
Args.notNull(credentials, "Credentials");
Args.notNull(request, "HTTP request");
final StringBuilder tmp = new StringBuilder();
tmp.append(credentials.getUserPrincipal().getName());
tmp.append(":");
tmp.append((credentials.getPassword() == null) ? "null" : credentials.getPassword());
final Base64 base64codec = new Base64(0);
final byte[] base64password = base64codec.encode(
EncodingUtils.getBytes(tmp.toString(), getCredentialsCharset(request)));
final CharArrayBuffer buffer = new CharArrayBuffer(32);
if (isProxy()) {
buffer.append(AUTH.PROXY_AUTH_RESP);
@ -150,16 +112,34 @@ public class BasicScheme extends RFC2617Scheme {
buffer.append(AUTH.WWW_AUTH_RESP);
}
buffer.append(": Basic ");
buffer.append(base64password, 0, base64password.length);
final StringBuilder tmp = new StringBuilder();
tmp.append(credentials.getUserPrincipal().getName());
tmp.append(":");
tmp.append((credentials.getPassword() == null) ? "null" : credentials.getPassword());
final Base64 base64codec = new Base64(0);
final byte[] base64password = base64codec.encode(EncodingUtils.getBytes(tmp.toString(), charset.name()));
buffer.append(base64password, 0, base64password.length);
return new BufferedHeader(buffer);
}
@Override
public String toString() {
final StringBuilder builder = new StringBuilder();
builder.append("BASIC [complete=").append(complete)
.append("]");
return builder.toString();
private void writeObject(final ObjectOutputStream out) throws IOException {
out.defaultWriteObject();
out.writeUTF(this.charset.name());
}
@SuppressWarnings("unchecked")
private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException {
in.defaultReadObject();
this.charset = CharsetUtils.get(in.readUTF());
if (this.charset == null) {
this.charset = Consts.ASCII;
}
}
private void readObjectNoData() throws ObjectStreamException {
}
}

View File

@ -27,7 +27,6 @@
package org.apache.http.impl.auth;
import java.io.IOException;
import java.nio.charset.Charset;
import java.security.MessageDigest;
import java.security.SecureRandom;
import java.util.ArrayList;
@ -38,14 +37,15 @@ import java.util.Locale;
import java.util.Set;
import java.util.StringTokenizer;
import org.apache.http.Consts;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpEntityEnclosingRequest;
import org.apache.http.HttpRequest;
import org.apache.http.annotation.NotThreadSafe;
import org.apache.http.auth.AUTH;
import org.apache.http.auth.AuthChallenge;
import org.apache.http.auth.AuthenticationException;
import org.apache.http.auth.ChallengeType;
import org.apache.http.auth.Credentials;
import org.apache.http.auth.MalformedChallengeException;
import org.apache.http.message.BasicHeaderValueFormatter;
@ -71,7 +71,7 @@ import org.apache.http.util.EncodingUtils;
* @since 4.0
*/
@NotThreadSafe
public class DigestScheme extends RFC2617Scheme {
public class DigestScheme extends StandardAuthScheme {
private static final long serialVersionUID = 3883908186234566916L;
@ -100,42 +100,23 @@ public class DigestScheme extends RFC2617Scheme {
private String a1;
private String a2;
/**
* @since 4.3
*/
public DigestScheme(final Charset credentialsCharset) {
super(credentialsCharset);
public DigestScheme() {
this.complete = false;
}
public DigestScheme() {
this(Consts.ASCII);
}
/**
* Processes the Digest challenge.
*
* @param header the challenge header
*
* @throws MalformedChallengeException is thrown if the authentication challenge
* is malformed
*/
@Override
public void processChallenge(
final Header header) throws MalformedChallengeException {
super.processChallenge(header);
this.complete = true;
final ChallengeType challengeType,
final AuthChallenge authChallenge) throws MalformedChallengeException {
Args.notNull(challengeType, "ChallengeType");
Args.notNull(authChallenge, "AuthChallenge");
update(challengeType, authChallenge);
if (getParameters().isEmpty()) {
throw new MalformedChallengeException("Authentication challenge is empty");
throw new MalformedChallengeException("Missing digest auth parameters");
}
this.complete = true;
}
/**
* Tests if the Digest authentication process has been completed.
*
* @return {@code true} if Digest authorization has been processed,
* {@code false} otherwise.
*/
@Override
public boolean isComplete() {
final String s = getParameter("stale");
@ -146,21 +127,11 @@ public class DigestScheme extends RFC2617Scheme {
}
}
/**
* Returns textual designation of the digest authentication scheme.
*
* @return {@code digest}
*/
@Override
public String getSchemeName() {
return "digest";
}
/**
* Returns {@code false}. Digest authentication scheme is request based.
*
* @return {@code false}.
*/
@Override
public boolean isConnectionBased() {
return false;
@ -170,20 +141,6 @@ public class DigestScheme extends RFC2617Scheme {
getParameters().put(name, value);
}
/**
* Produces a digest authorization string for the given set of
* {@link Credentials}, method name and URI.
*
* @param credentials A set of credentials to be used for athentication
* @param request The request being authenticated
*
* @throws org.apache.http.auth.InvalidCredentialsException if authentication credentials
* are not valid or not applicable for this authentication scheme
* @throws AuthenticationException if authorization string cannot
* be generated due to an authentication failure
*
* @return a digest authorization string
*/
@Override
public Header authenticate(
final Credentials credentials,
@ -201,10 +158,6 @@ public class DigestScheme extends RFC2617Scheme {
// Add method name and request-URI to the parameter map
getParameters().put("methodname", request.getRequestLine().getMethod());
getParameters().put("uri", request.getRequestLine().getUri());
final String charset = getParameter("charset");
if (charset == null) {
getParameters().put("charset", getCredentialsCharset(request));
}
return createDigestHeader(credentials, request);
}
@ -219,13 +172,6 @@ public class DigestScheme extends RFC2617Scheme {
}
}
/**
* Creates digest-response header as defined in RFC2617.
*
* @param credentials User credentials
*
* @return The digest-response as String.
*/
private Header createDigestHeader(
final Credentials credentials,
final HttpRequest request) throws AuthenticationException {
@ -447,7 +393,6 @@ public class DigestScheme extends RFC2617Scheme {
return new String(buffer);
}
/**
* Creates a random cnonce value based on the current time.
*
@ -460,14 +405,4 @@ public class DigestScheme extends RFC2617Scheme {
return encode(tmp);
}
@Override
public String toString() {
final StringBuilder builder = new StringBuilder();
builder.append("DIGEST [complete=").append(complete)
.append(", nonce=").append(lastNonce)
.append(", nc=").append(nounceCount)
.append("]");
return builder.toString();
}
}

View File

@ -27,8 +27,6 @@
package org.apache.http.impl.auth;
import java.nio.charset.Charset;
import org.apache.http.annotation.Immutable;
import org.apache.http.auth.AuthScheme;
import org.apache.http.auth.AuthSchemeProvider;
@ -43,23 +41,9 @@ import org.apache.http.protocol.HttpContext;
@Immutable
public class DigestSchemeFactory implements AuthSchemeProvider {
private final Charset charset;
/**
* @since 4.3
*/
public DigestSchemeFactory(final Charset charset) {
super();
this.charset = charset;
}
public DigestSchemeFactory() {
this(null);
}
@Override
public AuthScheme create(final HttpContext context) {
return new DigestScheme(this.charset);
return new DigestScheme();
}
}

View File

@ -37,7 +37,9 @@ import org.apache.http.HttpHost;
import org.apache.http.HttpRequest;
import org.apache.http.annotation.NotThreadSafe;
import org.apache.http.auth.AUTH;
import org.apache.http.auth.AuthChallenge;
import org.apache.http.auth.AuthenticationException;
import org.apache.http.auth.ChallengeType;
import org.apache.http.auth.Credentials;
import org.apache.http.auth.InvalidCredentialsException;
import org.apache.http.auth.KerberosCredentials;
@ -59,7 +61,7 @@ import org.ietf.jgss.Oid;
* @since 4.2
*/
@NotThreadSafe
public abstract class GGSSchemeBase extends AuthSchemeBase {
public abstract class GGSSchemeBase extends NonStandardAuthScheme {
enum State {
UNINITIATED,
@ -70,7 +72,6 @@ public abstract class GGSSchemeBase extends AuthSchemeBase {
private final Log log = LogFactory.getLog(getClass());
private final Base64 base64codec;
private final boolean stripPort;
private final boolean useCanonicalHostname;
@ -82,7 +83,6 @@ public abstract class GGSSchemeBase extends AuthSchemeBase {
GGSSchemeBase(final boolean stripPort, final boolean useCanonicalHostname) {
super();
this.base64codec = new Base64(0);
this.stripPort = stripPort;
this.useCanonicalHostname = useCanonicalHostname;
this.state = State.UNINITIATED;
@ -96,6 +96,23 @@ public abstract class GGSSchemeBase extends AuthSchemeBase {
this(true,true);
}
public void processChallenge(
final ChallengeType challengeType,
final AuthChallenge authChallenge) throws MalformedChallengeException {
update(challengeType, authChallenge);
if (state == State.UNINITIATED) {
final String challenge = getChallenge();
token = Base64.decodeBase64(challenge.getBytes());
if (log.isDebugEnabled()) {
log.debug("Received token '" + token + "' from the auth server");
}
state = State.CHALLENGE_RECEIVED;
} else {
log.debug("Authentication already attempted");
state = State.FAILED;
}
}
protected GSSManager getManager() {
return GSSManager.getInstance();
}
@ -211,7 +228,8 @@ public abstract class GGSSchemeBase extends AuthSchemeBase {
throw new AuthenticationException(gsse.getMessage());
}
case TOKEN_GENERATED:
final String tokenstr = new String(base64codec.encode(token));
final Base64 codec = new Base64(0);
final String tokenstr = new String(codec.encode(token));
if (log.isDebugEnabled()) {
log.debug("Sending response '" + tokenstr + "' back to the auth server");
}
@ -229,23 +247,6 @@ public abstract class GGSSchemeBase extends AuthSchemeBase {
}
}
@Override
protected void parseChallenge(
final CharArrayBuffer buffer,
final int beginIndex, final int endIndex) throws MalformedChallengeException {
final String challenge = buffer.substringTrimmed(beginIndex, endIndex);
if (log.isDebugEnabled()) {
log.debug("Received challenge '" + challenge + "' from the auth server");
}
if (state == State.UNINITIATED) {
token = Base64.decodeBase64(challenge.getBytes());
state = State.CHALLENGE_RECEIVED;
} else {
log.debug("Authentication already attempted");
state = State.FAILED;
}
}
private String resolveCanonicalHostname(final String host) throws UnknownHostException {
final InetAddress in = InetAddress.getByName(host);
final String canonicalServer = in.getCanonicalHostName();

View File

@ -28,27 +28,40 @@
package org.apache.http.impl.auth;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Queue;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.http.FormattedHeader;
import org.apache.http.Header;
import org.apache.http.HttpException;
import org.apache.http.HttpHeaders;
import org.apache.http.HttpHost;
import org.apache.http.HttpRequest;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.ParseException;
import org.apache.http.auth.AuthChallenge;
import org.apache.http.auth.AuthOption;
import org.apache.http.auth.AuthProtocolState;
import org.apache.http.auth.AuthScheme;
import org.apache.http.auth.AuthState;
import org.apache.http.auth.AuthenticationException;
import org.apache.http.auth.ChallengeType;
import org.apache.http.auth.Credentials;
import org.apache.http.auth.MalformedChallengeException;
import org.apache.http.client.AuthCache;
import org.apache.http.client.AuthenticationStrategy;
import org.apache.http.client.config.AuthSchemes;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.message.ParserCursor;
import org.apache.http.protocol.HttpContext;
import org.apache.http.util.Asserts;
import org.apache.http.util.CharArrayBuffer;
/**
* @since 4.3
@ -56,26 +69,39 @@ import org.apache.http.util.Asserts;
public class HttpAuthenticator {
private final Log log;
private final AuthChallengeParser parser;
public HttpAuthenticator(final Log log) {
super();
this.log = log != null ? log : LogFactory.getLog(getClass());
this.parser = new AuthChallengeParser();
}
public HttpAuthenticator() {
this(null);
}
public boolean isAuthenticationRequested(
public boolean updateAuthState(
final HttpHost host,
final ChallengeType challengeType,
final HttpResponse response,
final AuthenticationStrategy authStrategy,
final AuthState authState,
final HttpContext context) {
if (authStrategy.isAuthenticationRequested(host, response, context)) {
final int challengeCode;
switch (challengeType) {
case TARGET:
challengeCode = HttpStatus.SC_UNAUTHORIZED;
break;
case PROXY:
challengeCode = HttpStatus.SC_PROXY_AUTHENTICATION_REQUIRED;
break;
default:
throw new IllegalStateException("Unexpected challenge type: " + challengeType);
}
if (response.getStatusLine().getStatusCode() == challengeCode) {
this.log.debug("Authentication required");
if (authState.getState() == AuthProtocolState.SUCCESS) {
authStrategy.authFailed(host, authState.getAuthScheme(), context);
clearCache(host, context);
}
return true;
} else {
@ -84,7 +110,7 @@ public class HttpAuthenticator {
case HANDSHAKE:
this.log.debug("Authentication succeeded");
authState.setState(AuthProtocolState.SUCCESS);
authStrategy.authSucceeded(host, authState.getAuthScheme(), context);
updateCache(host, authState.getAuthScheme(), context);
break;
case SUCCESS:
break;
@ -97,17 +123,55 @@ public class HttpAuthenticator {
public boolean handleAuthChallenge(
final HttpHost host,
final ChallengeType challengeType,
final HttpResponse response,
final AuthenticationStrategy authStrategy,
final AuthState authState,
final HttpContext context) {
if (this.log.isDebugEnabled()) {
this.log.debug(host.toHostString() + " requested authentication");
}
try {
if (this.log.isDebugEnabled()) {
this.log.debug(host.toHostString() + " requested authentication");
final Header[] headers = response.getHeaders(
challengeType == ChallengeType.PROXY ? HttpHeaders.PROXY_AUTHENTICATE : HttpHeaders.WWW_AUTHENTICATE);
final Map<String, AuthChallenge> challengeMap = new HashMap<>();
for (Header header: headers) {
final CharArrayBuffer buffer;
final int pos;
if (header instanceof FormattedHeader) {
buffer = ((FormattedHeader) header).getBuffer();
pos = ((FormattedHeader) header).getValuePos();
} else {
final String s = header.getValue();
if (s == null) {
continue;
}
buffer = new CharArrayBuffer(s.length());
buffer.append(s);
pos = 0;
}
final ParserCursor cursor = new ParserCursor(pos, buffer.length());
final List<AuthChallenge> authChallenges;
try {
authChallenges = parser.parse(buffer, cursor);
} catch (ParseException ex) {
if (this.log.isWarnEnabled()) {
this.log.warn("Malformed challenge: " + header.getValue());
}
continue;
}
for (AuthChallenge authChallenge: authChallenges) {
final String scheme = authChallenge.getScheme().toLowerCase(Locale.ROOT);
if (!challengeMap.containsKey(scheme)) {
challengeMap.put(scheme, authChallenge);
}
}
}
final Map<String, Header> challenges = authStrategy.getChallenges(host, response, context);
if (challenges.isEmpty()) {
this.log.debug("Response contains no authentication challenges");
if (challengeMap.isEmpty()) {
this.log.debug("Response contains no valid authentication challenges");
clearCache(host, context);
authState.reset();
return false;
}
@ -122,7 +186,7 @@ public class HttpAuthenticator {
case HANDSHAKE:
if (authScheme == null) {
this.log.debug("Auth scheme is null");
authStrategy.authFailed(host, null, context);
clearCache(host, context);
authState.reset();
authState.setState(AuthProtocolState.FAILURE);
return false;
@ -130,13 +194,13 @@ public class HttpAuthenticator {
case UNCHALLENGED:
if (authScheme != null) {
final String id = authScheme.getSchemeName();
final Header challenge = challenges.get(id.toLowerCase(Locale.ROOT));
final AuthChallenge challenge = challengeMap.get(id.toLowerCase(Locale.ROOT));
if (challenge != null) {
this.log.debug("Authorization challenge processed");
authScheme.processChallenge(challenge);
authScheme.processChallenge(challengeType, challenge);
if (authScheme.isComplete()) {
this.log.debug("Authentication failed");
authStrategy.authFailed(host, authState.getAuthScheme(), context);
clearCache(host, context);
authState.reset();
authState.setState(AuthProtocolState.FAILURE);
return false;
@ -150,7 +214,7 @@ public class HttpAuthenticator {
}
}
}
final Queue<AuthOption> authOptions = authStrategy.select(challenges, host, response, context);
final Queue<AuthOption> authOptions = authStrategy.select(challengeType, host, challengeMap, context);
if (authOptions != null && !authOptions.isEmpty()) {
if (this.log.isDebugEnabled()) {
this.log.debug("Selected authentication options: " + authOptions);
@ -180,7 +244,7 @@ public class HttpAuthenticator {
case FAILURE:
return;
case SUCCESS:
ensureAuthScheme(authScheme);
Asserts.notNull(authScheme, "AuthScheme");
if (authScheme.isConnectionBased()) {
return;
}
@ -209,7 +273,7 @@ public class HttpAuthenticator {
}
return;
} else {
ensureAuthScheme(authScheme);
Asserts.notNull(authScheme, "AuthScheme");
}
}
if (authScheme != null) {
@ -224,8 +288,35 @@ public class HttpAuthenticator {
}
}
private void ensureAuthScheme(final AuthScheme authScheme) {
Asserts.notNull(authScheme, "Auth scheme");
private boolean isCachable(final AuthScheme authScheme) {
final String schemeName = authScheme.getSchemeName();
return schemeName.equalsIgnoreCase(AuthSchemes.BASIC) ||
schemeName.equalsIgnoreCase(AuthSchemes.DIGEST);
}
private void updateCache(final HttpHost host, final AuthScheme authScheme, final HttpContext context) {
if (isCachable(authScheme)) {
final HttpClientContext clientContext = HttpClientContext.adapt(context);
final AuthCache authCache = clientContext.getAuthCache();
if (authCache != null) {
if (this.log.isDebugEnabled()) {
this.log.debug("Caching '" + authScheme.getSchemeName() + "' auth scheme for " + host);
}
authCache.put(host, authScheme);
}
}
}
private void clearCache(final HttpHost host, final HttpContext context) {
final HttpClientContext clientContext = HttpClientContext.adapt(context);
final AuthCache authCache = clientContext.getAuthCache();
if (authCache != null) {
if (this.log.isDebugEnabled()) {
this.log.debug("Clearing cached auth scheme for " + host);
}
authCache.remove(host);
}
}
private Header doAuth(

View File

@ -26,13 +26,8 @@
*/
package org.apache.http.impl.auth;
import org.apache.http.Header;
import org.apache.http.HttpRequest;
import org.apache.http.annotation.NotThreadSafe;
import org.apache.http.auth.AuthenticationException;
import org.apache.http.auth.Credentials;
import org.apache.http.protocol.HttpContext;
import org.apache.http.util.Args;
import org.ietf.jgss.GSSException;
import org.ietf.jgss.Oid;
@ -66,59 +61,11 @@ public class KerberosScheme extends GGSSchemeBase {
return "Kerberos";
}
/**
* Produces KERBEROS authorization Header based on token created by
* processChallenge.
*
* @param credentials not used by the KERBEROS scheme.
* @param request The request being authenticated
*
* @throws AuthenticationException if authentication string cannot
* be generated due to an authentication failure
*
* @return KERBEROS authentication Header
*/
@Override
public Header authenticate(
final Credentials credentials,
final HttpRequest request,
final HttpContext context) throws AuthenticationException {
return super.authenticate(credentials, request, context);
}
@Override
protected byte[] generateToken(final byte[] input, final String authServer, final Credentials credentials) throws GSSException {
return generateGSSToken(input, new Oid(KERBEROS_OID), authServer, credentials);
}
/**
* There are no valid parameters for KERBEROS authentication so this
* method always returns {@code null}.
*
* @return {@code null}
*/
@Override
public String getParameter(final String name) {
Args.notNull(name, "Parameter name");
return null;
}
/**
* The concept of an authentication realm is not supported by the Negotiate
* authentication scheme. Always returns {@code null}.
*
* @return {@code null}
*/
@Override
public String getRealm() {
return null;
}
/**
* Returns {@code true}. KERBEROS authentication scheme is connection based.
*
* @return {@code true}.
*/
@Override
public boolean isConnectionBased() {
return true;

View File

@ -30,7 +30,9 @@ import org.apache.http.Header;
import org.apache.http.HttpRequest;
import org.apache.http.annotation.NotThreadSafe;
import org.apache.http.auth.AUTH;
import org.apache.http.auth.AuthChallenge;
import org.apache.http.auth.AuthenticationException;
import org.apache.http.auth.ChallengeType;
import org.apache.http.auth.Credentials;
import org.apache.http.auth.InvalidCredentialsException;
import org.apache.http.auth.MalformedChallengeException;
@ -47,7 +49,7 @@ import org.apache.http.util.CharArrayBuffer;
* @since 4.0
*/
@NotThreadSafe
public class NTLMScheme extends AuthSchemeBase {
public class NTLMScheme extends NonStandardAuthScheme {
enum State {
UNINITIATED,
@ -61,14 +63,12 @@ public class NTLMScheme extends AuthSchemeBase {
private final NTLMEngine engine;
private State state;
private String challenge;
public NTLMScheme(final NTLMEngine engine) {
super();
Args.notNull(engine, "NTLM engine");
this.engine = engine;
this.state = State.UNINITIATED;
this.challenge = null;
}
/**
@ -83,29 +83,18 @@ public class NTLMScheme extends AuthSchemeBase {
return "ntlm";
}
@Override
public String getParameter(final String name) {
// String parameters not supported
return null;
}
@Override
public String getRealm() {
// NTLM does not support the concept of an authentication realm
return null;
}
@Override
public boolean isConnectionBased() {
return true;
}
@Override
protected void parseChallenge(
final CharArrayBuffer buffer,
final int beginIndex, final int endIndex) throws MalformedChallengeException {
this.challenge = buffer.substringTrimmed(beginIndex, endIndex);
if (this.challenge.isEmpty()) {
public void processChallenge(
final ChallengeType challengeType, final AuthChallenge authChallenge) throws MalformedChallengeException {
Args.notNull(challengeType, "ChallengeType");
Args.notNull(authChallenge, "AuthChallenge");
final String value = authChallenge.getValue();
if (value == null || value.isEmpty()) {
if (this.state == State.UNINITIATED) {
this.state = State.CHALLENGE_RECEIVED;
} else {
@ -126,7 +115,7 @@ public class NTLMScheme extends AuthSchemeBase {
final Credentials credentials,
final HttpRequest request,
final HttpContext context) throws AuthenticationException {
NTCredentials ntcredentials = null;
final NTCredentials ntcredentials;
try {
ntcredentials = (NTCredentials) credentials;
} catch (final ClassCastException e) {
@ -134,7 +123,7 @@ public class NTLMScheme extends AuthSchemeBase {
"Credentials cannot be used for NTLM authentication: "
+ credentials.getClass().getName());
}
String response = null;
final String response;
if (this.state == State.FAILED) {
throw new AuthenticationException("NTLM authentication failed");
} else if (this.state == State.CHALLENGE_RECEIVED) {
@ -148,7 +137,7 @@ public class NTLMScheme extends AuthSchemeBase {
ntcredentials.getPassword(),
ntcredentials.getNetbiosDomain(),
ntcredentials.getWorkstation(),
this.challenge);
getChallenge());
this.state = State.MSG_TYPE3_GENERATED;
} else {
throw new AuthenticationException("Unexpected state: " + this.state);

View File

@ -24,34 +24,47 @@
* <http://www.apache.org/>.
*
*/
package org.apache.http.impl.auth;
package org.apache.http.impl.client;
import org.apache.http.auth.AuthChallenge;
import org.apache.http.auth.AuthScheme;
import org.apache.http.auth.ChallengeType;
import org.apache.http.auth.MalformedChallengeException;
import java.util.Collection;
public abstract class NonStandardAuthScheme implements AuthScheme {
import org.apache.http.HttpStatus;
import org.apache.http.annotation.Immutable;
import org.apache.http.auth.AUTH;
import org.apache.http.client.config.RequestConfig;
private ChallengeType challengeType;
private String challenge;
/**
* Default {@link org.apache.http.client.AuthenticationStrategy} implementation
* for proxy host authentication.
*
* @since 4.2
*/
@Immutable
public class ProxyAuthenticationStrategy extends AuthenticationStrategyImpl {
public boolean isProxy() {
return this.challengeType != null && this.challengeType == ChallengeType.PROXY;
}
public static final ProxyAuthenticationStrategy INSTANCE = new ProxyAuthenticationStrategy();
protected void update(final ChallengeType challengeType, final AuthChallenge authChallenge) throws MalformedChallengeException{
if (authChallenge.getValue() == null) {
throw new MalformedChallengeException("Missing auth challenge");
}
this.challengeType = challengeType;
this.challenge = authChallenge.getValue();
}
public ProxyAuthenticationStrategy() {
super(HttpStatus.SC_PROXY_AUTHENTICATION_REQUIRED, AUTH.PROXY_AUTH);
protected String getChallenge() {
return this.challenge;
}
@Override
Collection<String> getPreferredAuthSchemes(final RequestConfig config) {
return config.getProxyPreferredAuthSchemes();
public String getParameter(final String name) {
return null;
}
@Override
public String getRealm() {
return null;
}
@Override
public String toString() {
return getSchemeName() + "(" + this.challengeType + ") " + this.challenge;
}
}

View File

@ -1,156 +0,0 @@
/*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
*/
package org.apache.http.impl.auth;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.ObjectStreamException;
import java.io.Serializable;
import java.nio.charset.Charset;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import org.apache.http.Consts;
import org.apache.http.HeaderElement;
import org.apache.http.HttpRequest;
import org.apache.http.annotation.NotThreadSafe;
import org.apache.http.auth.ChallengeState;
import org.apache.http.auth.MalformedChallengeException;
import org.apache.http.message.BasicHeaderValueParser;
import org.apache.http.message.HeaderValueParser;
import org.apache.http.message.ParserCursor;
import org.apache.http.util.CharArrayBuffer;
import org.apache.http.util.CharsetUtils;
/**
* Abstract authentication scheme class that lays foundation for all
* RFC 2617 compliant authentication schemes and provides capabilities common
* to all authentication schemes defined in RFC 2617.
*
* @since 4.0
*/
@NotThreadSafe // AuthSchemeBase, params
public abstract class RFC2617Scheme extends AuthSchemeBase implements Serializable {
private static final long serialVersionUID = -2845454858205884623L;
private final Map<String, String> params;
private transient Charset credentialsCharset;
/**
* @since 4.3
*/
public RFC2617Scheme(final Charset credentialsCharset) {
super();
this.params = new HashMap<>();
this.credentialsCharset = credentialsCharset != null ? credentialsCharset : Consts.ASCII;
}
public RFC2617Scheme() {
this(Consts.ASCII);
}
/**
* @since 4.3
*/
public Charset getCredentialsCharset() {
return credentialsCharset != null ? credentialsCharset : Consts.ASCII;
}
String getCredentialsCharset(final HttpRequest request) {
return getCredentialsCharset().name();
}
@Override
protected void parseChallenge(
final CharArrayBuffer buffer, final int pos, final int len) throws MalformedChallengeException {
final HeaderValueParser parser = BasicHeaderValueParser.INSTANCE;
final ParserCursor cursor = new ParserCursor(pos, buffer.length());
final HeaderElement[] elements = parser.parseElements(buffer, cursor);
this.params.clear();
for (final HeaderElement element : elements) {
this.params.put(element.getName().toLowerCase(Locale.ROOT), element.getValue());
}
}
/**
* Returns authentication parameters map. Keys in the map are lower-cased.
*
* @return the map of authentication parameters
*/
protected Map<String, String> getParameters() {
return this.params;
}
/**
* Returns authentication parameter with the given name, if available.
*
* @param name The name of the parameter to be returned
*
* @return the parameter with the given name
*/
@Override
public String getParameter(final String name) {
if (name == null) {
return null;
}
return this.params.get(name.toLowerCase(Locale.ROOT));
}
/**
* Returns authentication realm. The realm may not be null.
*
* @return the authentication realm
*/
@Override
public String getRealm() {
return getParameter("realm");
}
private void writeObject(final ObjectOutputStream out) throws IOException {
out.defaultWriteObject();
out.writeUTF(this.credentialsCharset.name());
out.writeObject(this.challengeState);
}
@SuppressWarnings("unchecked")
private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException {
in.defaultReadObject();
this.credentialsCharset = CharsetUtils.get(in.readUTF());
if (this.credentialsCharset == null) {
this.credentialsCharset = Consts.ASCII;
}
this.challengeState = (ChallengeState) in.readObject();
}
private void readObjectNoData() throws ObjectStreamException {
}
}

View File

@ -26,13 +26,8 @@
*/
package org.apache.http.impl.auth;
import org.apache.http.Header;
import org.apache.http.HttpRequest;
import org.apache.http.annotation.NotThreadSafe;
import org.apache.http.auth.AuthenticationException;
import org.apache.http.auth.Credentials;
import org.apache.http.protocol.HttpContext;
import org.apache.http.util.Args;
import org.ietf.jgss.GSSException;
import org.ietf.jgss.Oid;
@ -67,59 +62,11 @@ public class SPNegoScheme extends GGSSchemeBase {
return "Negotiate";
}
/**
* Produces SPNEGO authorization Header based on token created by
* processChallenge.
*
* @param credentials not used by the SPNEGO scheme.
* @param request The request being authenticated
*
* @throws AuthenticationException if authentication string cannot
* be generated due to an authentication failure
*
* @return SPNEGO authentication Header
*/
@Override
public Header authenticate(
final Credentials credentials,
final HttpRequest request,
final HttpContext context) throws AuthenticationException {
return super.authenticate(credentials, request, context);
}
@Override
protected byte[] generateToken(final byte[] input, final String authServer, final Credentials credentials) throws GSSException {
return generateGSSToken(input, new Oid(SPNEGO_OID), authServer, credentials);
}
/**
* There are no valid parameters for SPNEGO authentication so this
* method always returns {@code null}.
*
* @return {@code null}
*/
@Override
public String getParameter(final String name) {
Args.notNull(name, "Parameter name");
return null;
}
/**
* The concept of an authentication realm is not supported by the Negotiate
* authentication scheme. Always returns {@code null}.
*
* @return {@code null}
*/
@Override
public String getRealm() {
return null;
}
/**
* Returns {@code true}. SPNEGO authentication scheme is connection based.
*
* @return {@code true}.
*/
@Override
public boolean isConnectionBased() {
return true;

View File

@ -0,0 +1,111 @@
/*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
*/
package org.apache.http.impl.auth;
import java.io.Serializable;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import org.apache.http.NameValuePair;
import org.apache.http.annotation.NotThreadSafe;
import org.apache.http.auth.AuthChallenge;
import org.apache.http.auth.AuthScheme;
import org.apache.http.auth.ChallengeType;
import org.apache.http.auth.MalformedChallengeException;
/**
* Abstract authentication scheme class that lays foundation for standard HTTP authentication schemes and
* provides capabilities common to all authentication schemes defined in the HTTP specification.
*
* @since 4.0
*/
@NotThreadSafe
public abstract class StandardAuthScheme implements AuthScheme, Serializable {
private static final long serialVersionUID = -2845454858205884623L;
private final Map<String, String> paramMap;
private ChallengeType challengeType;
/**
* @since 4.3
*/
public StandardAuthScheme() {
super();
this.paramMap = new LinkedHashMap<>();
}
protected void update(final ChallengeType challengeType, final AuthChallenge authChallenge) throws MalformedChallengeException {
final List<NameValuePair> params = authChallenge.getParams();
this.challengeType = challengeType;
if (params != null) {
for (NameValuePair param: params) {
this.paramMap.put(param.getName().toLowerCase(Locale.ROOT), param.getValue());
}
}
}
@Override
public String getRealm() {
return getParameter("realm");
}
protected Map<String, String> getParameters() {
return this.paramMap;
}
/**
* Returns authentication parameter with the given name, if available.
*
* @param name The name of the parameter to be returned
*
* @return the parameter with the given name
*/
@Override
public String getParameter(final String name) {
if (name == null) {
return null;
}
return this.paramMap.get(name.toLowerCase(Locale.ROOT));
}
/**
* Returns {@code true} if authenticating against a proxy, {@code false}
* otherwise.
*/
public boolean isProxy() {
return this.challengeType != null && this.challengeType == ChallengeType.PROXY;
}
@Override
public String toString() {
return getSchemeName() + "(" + this.challengeType + ") " + this.paramMap;
}
}

View File

@ -30,7 +30,6 @@ package org.apache.http.impl.client;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
@ -39,34 +38,37 @@ import java.util.Queue;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.http.FormattedHeader;
import org.apache.http.Header;
import org.apache.http.HttpHost;
import org.apache.http.HttpResponse;
import org.apache.http.annotation.Immutable;
import org.apache.http.auth.AuthChallenge;
import org.apache.http.auth.AuthOption;
import org.apache.http.auth.AuthScheme;
import org.apache.http.auth.AuthSchemeProvider;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.ChallengeType;
import org.apache.http.auth.Credentials;
import org.apache.http.auth.CredentialsProvider;
import org.apache.http.auth.MalformedChallengeException;
import org.apache.http.client.AuthCache;
import org.apache.http.client.AuthenticationStrategy;
import org.apache.http.client.config.AuthSchemes;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.config.Lookup;
import org.apache.http.protocol.HTTP;
import org.apache.http.protocol.HttpContext;
import org.apache.http.util.Args;
import org.apache.http.util.CharArrayBuffer;
/**
* Default implementation of {@link AuthenticationStrategy}
*
* @since 5.0
*/
@Immutable
abstract class AuthenticationStrategyImpl implements AuthenticationStrategy {
public class DefaultAuthenticationStrategy implements AuthenticationStrategy {
private final Log log = LogFactory.getLog(getClass());
public static final DefaultAuthenticationStrategy INSTANCE = new DefaultAuthenticationStrategy();
private static final List<String> DEFAULT_SCHEME_PRIORITY =
Collections.unmodifiableList(Arrays.asList(
AuthSchemes.SPNEGO,
@ -75,82 +77,15 @@ abstract class AuthenticationStrategyImpl implements AuthenticationStrategy {
AuthSchemes.DIGEST,
AuthSchemes.BASIC));
private final int challengeCode;
private final String headerName;
/**
* @param challengeCode for example SC_PROXY_AUTHENTICATION_REQUIRED or SC_UNAUTHORIZED
* @param headerName for example "Proxy-Authenticate" or "WWW-Authenticate"
*/
AuthenticationStrategyImpl(final int challengeCode, final String headerName) {
super();
this.challengeCode = challengeCode;
this.headerName = headerName;
}
@Override
public boolean isAuthenticationRequested(
final HttpHost authhost,
final HttpResponse response,
final HttpContext context) {
Args.notNull(response, "HTTP response");
final int status = response.getStatusLine().getStatusCode();
return status == this.challengeCode;
}
/**
* Generates a map of challenge auth-scheme =&gt; Header entries.
*
* @return map: key=lower-cased auth-scheme name, value=Header that contains the challenge
*/
@Override
public Map<String, Header> getChallenges(
final HttpHost authhost,
final HttpResponse response,
final HttpContext context) throws MalformedChallengeException {
Args.notNull(response, "HTTP response");
final Header[] headers = response.getHeaders(this.headerName);
final Map<String, Header> map = new HashMap<>(headers.length);
for (final Header header : headers) {
final CharArrayBuffer buffer;
int pos;
if (header instanceof FormattedHeader) {
buffer = ((FormattedHeader) header).getBuffer();
pos = ((FormattedHeader) header).getValuePos();
} else {
final String s = header.getValue();
if (s == null) {
throw new MalformedChallengeException("Header value is null");
}
buffer = new CharArrayBuffer(s.length());
buffer.append(s);
pos = 0;
}
while (pos < buffer.length() && HTTP.isWhitespace(buffer.charAt(pos))) {
pos++;
}
final int beginIndex = pos;
while (pos < buffer.length() && !HTTP.isWhitespace(buffer.charAt(pos))) {
pos++;
}
final int endIndex = pos;
final String s = buffer.substring(beginIndex, endIndex);
map.put(s.toLowerCase(Locale.ROOT), header);
}
return map;
}
abstract Collection<String> getPreferredAuthSchemes(RequestConfig config);
@Override
public Queue<AuthOption> select(
final Map<String, Header> challenges,
final ChallengeType challengeType,
final HttpHost authhost,
final HttpResponse response,
final Map<String, AuthChallenge> challenges,
final HttpContext context) throws MalformedChallengeException {
Args.notNull(challengeType, "ChallengeType");
Args.notNull(challenges, "Map of auth challenges");
Args.notNull(authhost, "Host");
Args.notNull(response, "HTTP response");
Args.notNull(context, "HTTP context");
final HttpClientContext clientContext = HttpClientContext.adapt(context);
@ -166,7 +101,8 @@ abstract class AuthenticationStrategyImpl implements AuthenticationStrategy {
return options;
}
final RequestConfig config = clientContext.getRequestConfig();
Collection<String> authPrefs = getPreferredAuthSchemes(config);
Collection<String> authPrefs = challengeType == ChallengeType.TARGET ?
config.getTargetPreferredAuthSchemes() : config.getProxyPreferredAuthSchemes();
if (authPrefs == null) {
authPrefs = DEFAULT_SCHEME_PRIORITY;
}
@ -175,7 +111,7 @@ abstract class AuthenticationStrategyImpl implements AuthenticationStrategy {
}
for (final String id: authPrefs) {
final Header challenge = challenges.get(id.toLowerCase(Locale.ROOT));
final AuthChallenge challenge = challenges.get(id.toLowerCase(Locale.ROOT));
if (challenge != null) {
final AuthSchemeProvider authSchemeProvider = registry.lookup(id);
if (authSchemeProvider == null) {
@ -186,7 +122,7 @@ abstract class AuthenticationStrategyImpl implements AuthenticationStrategy {
continue;
}
final AuthScheme authScheme = authSchemeProvider.create(context);
authScheme.processChallenge(challenge);
authScheme.processChallenge(challengeType, challenge);
final AuthScope authScope = new AuthScope(
authhost.getHostName(),
@ -208,53 +144,4 @@ abstract class AuthenticationStrategyImpl implements AuthenticationStrategy {
return options;
}
@Override
public void authSucceeded(
final HttpHost authhost, final AuthScheme authScheme, final HttpContext context) {
Args.notNull(authhost, "Host");
Args.notNull(authScheme, "Auth scheme");
Args.notNull(context, "HTTP context");
final HttpClientContext clientContext = HttpClientContext.adapt(context);
if (isCachable(authScheme)) {
AuthCache authCache = clientContext.getAuthCache();
if (authCache == null) {
authCache = new BasicAuthCache();
clientContext.setAuthCache(authCache);
}
if (this.log.isDebugEnabled()) {
this.log.debug("Caching '" + authScheme.getSchemeName() +
"' auth scheme for " + authhost);
}
authCache.put(authhost, authScheme);
}
}
protected boolean isCachable(final AuthScheme authScheme) {
if (authScheme == null || !authScheme.isComplete()) {
return false;
}
final String schemeName = authScheme.getSchemeName();
return schemeName.equalsIgnoreCase(AuthSchemes.BASIC) ||
schemeName.equalsIgnoreCase(AuthSchemes.DIGEST);
}
@Override
public void authFailed(
final HttpHost authhost, final AuthScheme authScheme, final HttpContext context) {
Args.notNull(authhost, "Host");
Args.notNull(context, "HTTP context");
final HttpClientContext clientContext = HttpClientContext.adapt(context);
final AuthCache authCache = clientContext.getAuthCache();
if (authCache != null) {
if (this.log.isDebugEnabled()) {
this.log.debug("Clearing cached auth scheme for " + authhost);
}
authCache.remove(authhost);
}
}
}

View File

@ -949,11 +949,11 @@ public class HttpClientBuilder {
}
AuthenticationStrategy targetAuthStrategyCopy = this.targetAuthStrategy;
if (targetAuthStrategyCopy == null) {
targetAuthStrategyCopy = TargetAuthenticationStrategy.INSTANCE;
targetAuthStrategyCopy = DefaultAuthenticationStrategy.INSTANCE;
}
AuthenticationStrategy proxyAuthStrategyCopy = this.proxyAuthStrategy;
if (proxyAuthStrategyCopy == null) {
proxyAuthStrategyCopy = ProxyAuthenticationStrategy.INSTANCE;
proxyAuthStrategyCopy = DefaultAuthenticationStrategy.INSTANCE;
}
UserTokenHandler userTokenHandlerCopy = this.userTokenHandler;
if (userTokenHandlerCopy == null) {

View File

@ -41,7 +41,9 @@ import org.apache.http.auth.AUTH;
import org.apache.http.auth.AuthSchemeProvider;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.AuthState;
import org.apache.http.auth.ChallengeType;
import org.apache.http.auth.Credentials;
import org.apache.http.client.AuthenticationStrategy;
import org.apache.http.client.config.AuthSchemes;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.protocol.HttpClientContext;
@ -86,7 +88,7 @@ public class ProxyClient {
private final RequestConfig requestConfig;
private final HttpProcessor httpProcessor;
private final HttpRequestExecutor requestExec;
private final ProxyAuthenticationStrategy proxyAuthStrategy;
private final AuthenticationStrategy proxyAuthStrategy;
private final HttpAuthenticator authenticator;
private final AuthState proxyAuthState;
private final Lookup<AuthSchemeProvider> authSchemeRegistry;
@ -106,7 +108,7 @@ public class ProxyClient {
this.httpProcessor = new ImmutableHttpProcessor(
new RequestTargetHost(), new RequestClientConnControl(), new RequestUserAgent());
this.requestExec = new HttpRequestExecutor();
this.proxyAuthStrategy = new ProxyAuthenticationStrategy();
this.proxyAuthStrategy = new DefaultAuthenticationStrategy();
this.authenticator = new HttpAuthenticator();
this.proxyAuthState = new AuthState();
this.authSchemeRegistry = RegistryBuilder.<AuthSchemeProvider>create()
@ -184,9 +186,8 @@ public class ProxyClient {
throw new HttpException("Unexpected response to CONNECT request: " +
response.getStatusLine());
}
if (this.authenticator.isAuthenticationRequested(proxy, response,
this.proxyAuthStrategy, this.proxyAuthState, context)) {
if (this.authenticator.handleAuthChallenge(proxy, response,
if (this.authenticator.updateAuthState(proxy, ChallengeType.PROXY, response, this.proxyAuthState, context)) {
if (this.authenticator.handleAuthChallenge(proxy, ChallengeType.PROXY, response,
this.proxyAuthStrategy, this.proxyAuthState, context)) {
// Retry request
if (this.reuseStrategy.keepAlive(response, context)) {

View File

@ -1,57 +0,0 @@
/*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
*/
package org.apache.http.impl.client;
import java.util.Collection;
import org.apache.http.HttpStatus;
import org.apache.http.annotation.Immutable;
import org.apache.http.auth.AUTH;
import org.apache.http.client.config.RequestConfig;
/**
* Default {@link org.apache.http.client.AuthenticationStrategy} implementation
* for proxy host authentication.
*
* @since 4.2
*/
@Immutable
public class TargetAuthenticationStrategy extends AuthenticationStrategyImpl {
public static final TargetAuthenticationStrategy INSTANCE = new TargetAuthenticationStrategy();
public TargetAuthenticationStrategy() {
super(HttpStatus.SC_UNAUTHORIZED, AUTH.WWW_AUTH);
}
@Override
Collection<String> getPreferredAuthSchemes(final RequestConfig config) {
return config.getTargetPreferredAuthSchemes();
}
}

View File

@ -46,6 +46,7 @@ import org.apache.http.annotation.Immutable;
import org.apache.http.auth.AUTH;
import org.apache.http.auth.AuthProtocolState;
import org.apache.http.auth.AuthState;
import org.apache.http.auth.ChallengeType;
import org.apache.http.client.AuthenticationStrategy;
import org.apache.http.client.NonRepeatableRequestException;
import org.apache.http.client.UserTokenHandler;
@ -465,9 +466,9 @@ public class MainClientExec implements ClientExecChain {
}
if (config.isAuthenticationEnabled()) {
if (this.authenticator.isAuthenticationRequested(proxy, response,
this.proxyAuthStrategy, proxyAuthState, context)) {
if (this.authenticator.handleAuthChallenge(proxy, response,
if (this.authenticator.updateAuthState(proxy, ChallengeType.PROXY, response,
proxyAuthState, context)) {
if (this.authenticator.handleAuthChallenge(proxy, ChallengeType.PROXY, response,
this.proxyAuthStrategy, proxyAuthState, context)) {
// Retry request
if (this.reuseStrategy.keepAlive(response, context)) {
@ -546,23 +547,23 @@ public class MainClientExec implements ClientExecChain {
route.getTargetHost().getPort(),
target.getSchemeName());
}
final boolean targetAuthRequested = this.authenticator.isAuthenticationRequested(
target, response, this.targetAuthStrategy, targetAuthState, context);
final boolean targetAuthRequested = this.authenticator.updateAuthState(
target, ChallengeType.TARGET, response, targetAuthState, context);
HttpHost proxy = route.getProxyHost();
// if proxy is not set use target host instead
if (proxy == null) {
proxy = route.getTargetHost();
}
final boolean proxyAuthRequested = this.authenticator.isAuthenticationRequested(
proxy, response, this.proxyAuthStrategy, proxyAuthState, context);
final boolean proxyAuthRequested = this.authenticator.updateAuthState(
proxy, ChallengeType.PROXY, response, proxyAuthState, context);
if (targetAuthRequested) {
return this.authenticator.handleAuthChallenge(target, response,
return this.authenticator.handleAuthChallenge(target, ChallengeType.TARGET, response,
this.targetAuthStrategy, targetAuthState, context);
}
if (proxyAuthRequested) {
return this.authenticator.handleAuthChallenge(proxy, response,
return this.authenticator.handleAuthChallenge(proxy, ChallengeType.PROXY, response,
this.proxyAuthStrategy, proxyAuthState, context);
}
}

View File

@ -58,6 +58,17 @@ public class TestAuthChallengeParser {
Assert.assertEquals(null, nvp.getValue());
}
@Test
public void testParseTokenWithBlank() throws Exception {
final CharArrayBuffer buffer = new CharArrayBuffer(64);
buffer.append("blah ");
final ParserCursor cursor = new ParserCursor(0, buffer.length());
final NameValuePair nvp = parser.parseTokenOrParameter(buffer, cursor);
Assert.assertNotNull(nvp);
Assert.assertEquals("blah", nvp.getName());
Assert.assertEquals(null, nvp.getValue());
}
@Test
public void testParseTokenWithBlanks() throws Exception {
final CharArrayBuffer buffer = new CharArrayBuffer(64);

View File

@ -30,18 +30,22 @@ import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.List;
import org.apache.commons.codec.binary.Base64;
import org.apache.http.Consts;
import org.apache.http.Header;
import org.apache.http.HttpRequest;
import org.apache.http.auth.AUTH;
import org.apache.http.auth.AuthChallenge;
import org.apache.http.auth.AuthScheme;
import org.apache.http.auth.ChallengeType;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.message.BasicHeader;
import org.apache.http.message.BasicHttpRequest;
import org.apache.http.message.ParserCursor;
import org.apache.http.protocol.BasicHttpContext;
import org.apache.http.protocol.HttpContext;
import org.apache.http.util.CharArrayBuffer;
import org.apache.http.util.EncodingUtils;
import org.junit.Assert;
import org.junit.Test;
@ -51,12 +55,21 @@ import org.junit.Test;
*/
public class TestBasicScheme {
private static AuthChallenge parse(final String s) {
final CharArrayBuffer buffer = new CharArrayBuffer(s.length());
buffer.append(s);
final ParserCursor cursor = new ParserCursor(0, buffer.length());
final List<AuthChallenge> authChallenges = AuthChallengeParser.INSTANCE.parse(buffer, cursor);
Assert.assertEquals(1, authChallenges.size());
return authChallenges.get(0);
}
@Test
public void testBasicAuthenticationEmptyChallenge() throws Exception {
final String challenge = "Basic";
final Header header = new BasicHeader(AUTH.WWW_AUTH, challenge);
final AuthChallenge authChallenge = parse(challenge);
final AuthScheme authscheme = new BasicScheme();
authscheme.processChallenge(header);
authscheme.processChallenge(ChallengeType.TARGET, authChallenge);
Assert.assertNull(authscheme.getRealm());
}
@ -79,13 +92,12 @@ public class TestBasicScheme {
@Test
public void testBasicAuthentication() throws Exception {
final UsernamePasswordCredentials creds =
new UsernamePasswordCredentials("testuser", "testpass");
final UsernamePasswordCredentials creds = new UsernamePasswordCredentials("testuser", "testpass");
final Header challenge = new BasicHeader(AUTH.WWW_AUTH, "Basic realm=\"test\"");
final AuthChallenge authChallenge = parse("Basic realm=\"test\"");
final BasicScheme authscheme = new BasicScheme();
authscheme.processChallenge(challenge);
authscheme.processChallenge(ChallengeType.TARGET, authChallenge);
final HttpRequest request = new BasicHttpRequest("GET", "/");
final HttpContext context = new BasicHttpContext();
@ -102,13 +114,12 @@ public class TestBasicScheme {
@Test
public void testBasicProxyAuthentication() throws Exception {
final UsernamePasswordCredentials creds =
new UsernamePasswordCredentials("testuser", "testpass");
final UsernamePasswordCredentials creds = new UsernamePasswordCredentials("testuser", "testpass");
final Header challenge = new BasicHeader(AUTH.PROXY_AUTH, "Basic realm=\"test\"");
final AuthChallenge authChallenge = parse("Basic realm=\"test\"");
final BasicScheme authscheme = new BasicScheme();
authscheme.processChallenge(challenge);
authscheme.processChallenge(ChallengeType.PROXY, authChallenge);
final HttpRequest request = new BasicHttpRequest("GET", "/");
final HttpContext context = new BasicHttpContext();
@ -125,10 +136,10 @@ public class TestBasicScheme {
@Test
public void testSerialization() throws Exception {
final Header challenge = new BasicHeader(AUTH.PROXY_AUTH, "Basic realm=\"test\"");
final AuthChallenge authChallenge = parse("Basic realm=\"test\"");
final BasicScheme basicScheme = new BasicScheme();
basicScheme.processChallenge(challenge);
basicScheme.processChallenge(ChallengeType.PROXY, authChallenge);
final ByteArrayOutputStream buffer = new ByteArrayOutputStream();
final ObjectOutputStream out = new ObjectOutputStream(buffer);

View File

@ -33,27 +33,30 @@ import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.security.MessageDigest;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.http.Header;
import org.apache.http.HeaderElement;
import org.apache.http.HttpEntityEnclosingRequest;
import org.apache.http.HttpRequest;
import org.apache.http.auth.AUTH;
import org.apache.http.auth.AuthChallenge;
import org.apache.http.auth.AuthScheme;
import org.apache.http.auth.AuthenticationException;
import org.apache.http.auth.ChallengeType;
import org.apache.http.auth.Credentials;
import org.apache.http.auth.MalformedChallengeException;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.entity.InputStreamEntity;
import org.apache.http.entity.StringEntity;
import org.apache.http.message.BasicHeader;
import org.apache.http.message.BasicHeaderValueParser;
import org.apache.http.message.BasicHttpEntityEnclosingRequest;
import org.apache.http.message.BasicHttpRequest;
import org.apache.http.message.ParserCursor;
import org.apache.http.protocol.BasicHttpContext;
import org.apache.http.protocol.HTTP;
import org.apache.http.protocol.HttpContext;
import org.apache.http.util.CharArrayBuffer;
import org.junit.Assert;
import org.junit.Test;
@ -62,29 +65,38 @@ import org.junit.Test;
*/
public class TestDigestScheme {
private static AuthChallenge parse(final String s) {
final CharArrayBuffer buffer = new CharArrayBuffer(s.length());
buffer.append(s);
final ParserCursor cursor = new ParserCursor(0, buffer.length());
final List<AuthChallenge> authChallenges = AuthChallengeParser.INSTANCE.parse(buffer, cursor);
Assert.assertEquals(1, authChallenges.size());
return authChallenges.get(0);
}
@Test(expected=MalformedChallengeException.class)
public void testDigestAuthenticationEmptyChallenge1() throws Exception {
final Header authChallenge = new BasicHeader(AUTH.WWW_AUTH, "Digest");
final AuthChallenge authChallenge = parse("Digest");
final AuthScheme authscheme = new DigestScheme();
authscheme.processChallenge(authChallenge);
authscheme.processChallenge(ChallengeType.TARGET, authChallenge);
}
@Test(expected=MalformedChallengeException.class)
public void testDigestAuthenticationEmptyChallenge2() throws Exception {
final Header authChallenge = new BasicHeader(AUTH.WWW_AUTH, "Digest ");
final AuthChallenge authChallenge = parse("Digest ");
final AuthScheme authscheme = new DigestScheme();
authscheme.processChallenge(authChallenge);
authscheme.processChallenge(ChallengeType.TARGET, authChallenge);
}
@Test
public void testDigestAuthenticationWithDefaultCreds() throws Exception {
final String challenge = "Digest realm=\"realm1\", nonce=\"f2a3f18799759d4f1a1c068b92b573cb\"";
final Header authChallenge = new BasicHeader(AUTH.WWW_AUTH, challenge);
final AuthChallenge authChallenge = parse(challenge);
final HttpRequest request = new BasicHttpRequest("Simple", "/");
final Credentials cred = new UsernamePasswordCredentials("username","password");
final DigestScheme authscheme = new DigestScheme();
final HttpContext context = new BasicHttpContext();
authscheme.processChallenge(authChallenge);
authscheme.processChallenge(ChallengeType.TARGET, authChallenge);
final Header authResponse = authscheme.authenticate(cred, request, context);
Assert.assertTrue(authscheme.isComplete());
Assert.assertFalse(authscheme.isConnectionBased());
@ -100,12 +112,12 @@ public class TestDigestScheme {
@Test
public void testDigestAuthentication() throws Exception {
final String challenge = "Digest realm=\"realm1\", nonce=\"f2a3f18799759d4f1a1c068b92b573cb\"";
final Header authChallenge = new BasicHeader(AUTH.WWW_AUTH, challenge);
final AuthChallenge authChallenge = parse(challenge);
final HttpRequest request = new BasicHttpRequest("Simple", "/");
final Credentials cred = new UsernamePasswordCredentials("username","password");
final DigestScheme authscheme = new DigestScheme();
final HttpContext context = new BasicHttpContext();
authscheme.processChallenge(authChallenge);
authscheme.processChallenge(ChallengeType.TARGET, authChallenge);
final Header authResponse = authscheme.authenticate(cred, request, context);
final Map<String, String> table = parseAuthResponse(authResponse);
@ -119,12 +131,12 @@ public class TestDigestScheme {
@Test
public void testDigestAuthenticationInvalidInput() throws Exception {
final String challenge = "Digest realm=\"realm1\", nonce=\"f2a3f18799759d4f1a1c068b92b573cb\"";
final Header authChallenge = new BasicHeader(AUTH.WWW_AUTH, challenge);
final AuthChallenge authChallenge = parse(challenge);
final HttpRequest request = new BasicHttpRequest("Simple", "/");
final Credentials cred = new UsernamePasswordCredentials("username","password");
final DigestScheme authscheme = new DigestScheme();
final HttpContext context = new BasicHttpContext();
authscheme.processChallenge(authChallenge);
authscheme.processChallenge(ChallengeType.TARGET, authChallenge);
try {
authscheme.authenticate(null, request, context);
Assert.fail("IllegalArgumentException should have been thrown");
@ -137,37 +149,17 @@ public class TestDigestScheme {
}
}
@Test
public void testDigestAuthenticationOverrideParameter() throws Exception {
final String challenge = "Digest realm=\"realm1\", nonce=\"f2a3f18799759d4f1a1c068b92b573cb\"";
final Header authChallenge = new BasicHeader(AUTH.WWW_AUTH, challenge);
final HttpRequest request = new BasicHttpRequest("Simple", "/");
final Credentials cred = new UsernamePasswordCredentials("username","password");
final DigestScheme authscheme = new DigestScheme();
final HttpContext context = new BasicHttpContext();
authscheme.processChallenge(authChallenge);
authscheme.overrideParamter("realm", "other realm");
final Header authResponse = authscheme.authenticate(cred, request, context);
final Map<String, String> table = parseAuthResponse(authResponse);
Assert.assertEquals("username", table.get("username"));
Assert.assertEquals("other realm", table.get("realm"));
Assert.assertEquals("/", table.get("uri"));
Assert.assertEquals("f2a3f18799759d4f1a1c068b92b573cb", table.get("nonce"));
Assert.assertEquals("3f211de10463cbd055ab4cd9c5158eac", table.get("response"));
}
@Test
public void testDigestAuthenticationWithSHA() throws Exception {
final String challenge = "Digest realm=\"realm1\", " +
"nonce=\"f2a3f18799759d4f1a1c068b92b573cb\", " +
"algorithm=SHA";
final Header authChallenge = new BasicHeader(AUTH.WWW_AUTH, challenge);
final AuthChallenge authChallenge = parse(challenge);
final HttpRequest request = new BasicHttpRequest("Simple", "/");
final Credentials cred = new UsernamePasswordCredentials("username","password");
final HttpContext context = new BasicHttpContext();
final DigestScheme authscheme = new DigestScheme();
authscheme.processChallenge(authChallenge);
authscheme.processChallenge(ChallengeType.TARGET, authChallenge);
final Header authResponse = authscheme.authenticate(cred, request, context);
final Map<String, String> table = parseAuthResponse(authResponse);
@ -181,12 +173,12 @@ public class TestDigestScheme {
@Test
public void testDigestAuthenticationWithQueryStringInDigestURI() throws Exception {
final String challenge = "Digest realm=\"realm1\", nonce=\"f2a3f18799759d4f1a1c068b92b573cb\"";
final Header authChallenge = new BasicHeader(AUTH.WWW_AUTH, challenge);
final AuthChallenge authChallenge = parse(challenge);
final HttpRequest request = new BasicHttpRequest("Simple", "/?param=value");
final Credentials cred = new UsernamePasswordCredentials("username","password");
final HttpContext context = new BasicHttpContext();
final DigestScheme authscheme = new DigestScheme();
authscheme.processChallenge(authChallenge);
authscheme.processChallenge(ChallengeType.TARGET, authChallenge);
final Header authResponse = authscheme.authenticate(cred, request, context);
final Map<String, String> table = parseAuthResponse(authResponse);
@ -204,11 +196,11 @@ public class TestDigestScheme {
final Credentials cred = new UsernamePasswordCredentials("username","password");
final Credentials cred2 = new UsernamePasswordCredentials("uname2","password2");
Header authChallenge = new BasicHeader(AUTH.WWW_AUTH, challenge1);
final AuthChallenge authChallenge1 = parse(challenge1);
final HttpRequest request = new BasicHttpRequest("Simple", "/");
final HttpContext context = new BasicHttpContext();
final DigestScheme authscheme = new DigestScheme();
authscheme.processChallenge(authChallenge);
authscheme.processChallenge(ChallengeType.TARGET, authChallenge1);
Header authResponse = authscheme.authenticate(cred, request, context);
Map<String, String> table = parseAuthResponse(authResponse);
@ -218,9 +210,9 @@ public class TestDigestScheme {
Assert.assertEquals("abcde", table.get("nonce"));
Assert.assertEquals("786f500303eac1478f3c2865e676ed68", table.get("response"));
authChallenge = new BasicHeader(AUTH.WWW_AUTH, challenge2);
final AuthChallenge authChallenge2 = parse(challenge2);
final DigestScheme authscheme2 = new DigestScheme();
authscheme2.processChallenge(authChallenge);
authscheme2.processChallenge(ChallengeType.TARGET, authChallenge2);
authResponse = authscheme2.authenticate(cred2, request, context);
table = parseAuthResponse(authResponse);
@ -234,10 +226,10 @@ public class TestDigestScheme {
@Test(expected=AuthenticationException.class)
public void testDigestAuthenticationNoRealm() throws Exception {
final String challenge = "Digest no-realm=\"realm1\", nonce=\"f2a3f18799759d4f1a1c068b92b573cb\"";
final Header authChallenge = new BasicHeader(AUTH.WWW_AUTH, challenge);
final AuthChallenge authChallenge = parse(challenge);
final HttpContext context = new BasicHttpContext();
final DigestScheme authscheme = new DigestScheme();
authscheme.processChallenge(authChallenge);
authscheme.processChallenge(ChallengeType.TARGET, authChallenge);
final Credentials cred = new UsernamePasswordCredentials("username","password");
final HttpRequest request = new BasicHttpRequest("Simple", "/");
@ -247,10 +239,10 @@ public class TestDigestScheme {
@Test(expected=AuthenticationException.class)
public void testDigestAuthenticationNoNonce() throws Exception {
final String challenge = "Digest realm=\"realm1\", no-nonce=\"f2a3f18799759d4f1a1c068b92b573cb\"";
final Header authChallenge = new BasicHeader(AUTH.WWW_AUTH, challenge);
final AuthChallenge authChallenge = parse(challenge);
final HttpContext context = new BasicHttpContext();
final DigestScheme authscheme = new DigestScheme();
authscheme.processChallenge(authChallenge);
authscheme.processChallenge(ChallengeType.TARGET, authChallenge);
final Credentials cred = new UsernamePasswordCredentials("username","password");
final HttpRequest request = new BasicHttpRequest("Simple", "/");
@ -276,14 +268,14 @@ public class TestDigestScheme {
+ "algorithm=MD5-sess, "
+ "qop=\"auth,auth-int\""; // we pass both but expect auth to be used
final Header authChallenge = new BasicHeader(AUTH.WWW_AUTH, challenge);
final AuthChallenge authChallenge = parse(challenge);
final Credentials cred = new UsernamePasswordCredentials(username, password);
final HttpRequest request = new BasicHttpRequest("Simple", "/");
final HttpContext context = new BasicHttpContext();
final DigestScheme authscheme = new DigestScheme();
authscheme.processChallenge(authChallenge);
authscheme.processChallenge(ChallengeType.TARGET, authChallenge);
final Header authResponse = authscheme.authenticate(cred, request, context);
final String response = authResponse.getValue();
@ -322,7 +314,7 @@ public class TestDigestScheme {
+ "stale=false, "
+ "algorithm=MD5-sess";
final Header authChallenge = new BasicHeader(AUTH.WWW_AUTH, challenge);
final AuthChallenge authChallenge = parse(challenge);
final Credentials cred = new UsernamePasswordCredentials(username, password);
@ -330,7 +322,7 @@ public class TestDigestScheme {
final HttpContext context = new BasicHttpContext();
final DigestScheme authscheme = new DigestScheme();
authscheme.processChallenge(authChallenge);
authscheme.processChallenge(ChallengeType.TARGET, authChallenge);
final Header authResponse = authscheme.authenticate(cred, request, context);
final Map<String, String> table = parseAuthResponse(authResponse);
@ -365,10 +357,10 @@ public class TestDigestScheme {
+ "algorithm=MD5-sess, "
+ "qop=\"stuff\"";
final Header authChallenge = new BasicHeader(AUTH.WWW_AUTH, challenge);
final AuthChallenge authChallenge = parse(challenge);
final DigestScheme authscheme = new DigestScheme();
authscheme.processChallenge(authChallenge);
authscheme.processChallenge(ChallengeType.TARGET, authChallenge);
final Credentials cred = new UsernamePasswordCredentials(username, password);
final HttpRequest request = new BasicHttpRequest("Simple", "/");
@ -395,10 +387,10 @@ public class TestDigestScheme {
+ "algorithm=stuff, "
+ "qop=\"auth\"";
final Header authChallenge = new BasicHeader(AUTH.WWW_AUTH, challenge);
final AuthChallenge authChallenge = parse(challenge);
final DigestScheme authscheme = new DigestScheme();
authscheme.processChallenge(authChallenge);
authscheme.processChallenge(ChallengeType.TARGET, authChallenge);
final Credentials cred = new UsernamePasswordCredentials(username, password);
final HttpRequest request = new BasicHttpRequest("Simple", "/");
@ -410,9 +402,9 @@ public class TestDigestScheme {
public void testDigestAuthenticationWithStaleNonce() throws Exception {
final String challenge = "Digest realm=\"realm1\", " +
"nonce=\"f2a3f18799759d4f1a1c068b92b573cb\", stale=\"true\"";
final Header authChallenge = new BasicHeader(AUTH.WWW_AUTH, challenge);
final AuthChallenge authChallenge = parse(challenge);
final AuthScheme authscheme = new DigestScheme();
authscheme.processChallenge(authChallenge);
authscheme.processChallenge(ChallengeType.TARGET, authChallenge);
Assert.assertFalse(authscheme.isComplete());
}
@ -433,12 +425,12 @@ public class TestDigestScheme {
@Test
public void testDigestNouceCount() throws Exception {
final String challenge1 = "Digest realm=\"realm1\", nonce=\"f2a3f18799759d4f1a1c068b92b573cb\", qop=auth";
final Header authChallenge1 = new BasicHeader(AUTH.WWW_AUTH, challenge1);
final AuthChallenge authChallenge1 = parse(challenge1);
final HttpRequest request = new BasicHttpRequest("GET", "/");
final Credentials cred = new UsernamePasswordCredentials("username","password");
final HttpContext context = new BasicHttpContext();
final DigestScheme authscheme = new DigestScheme();
authscheme.processChallenge(authChallenge1);
authscheme.processChallenge(ChallengeType.TARGET, authChallenge1);
final Header authResponse1 = authscheme.authenticate(cred, request, context);
final Map<String, String> table1 = parseAuthResponse(authResponse1);
Assert.assertEquals("00000001", table1.get("nc"));
@ -446,14 +438,14 @@ public class TestDigestScheme {
final Map<String, String> table2 = parseAuthResponse(authResponse2);
Assert.assertEquals("00000002", table2.get("nc"));
final String challenge2 = "Digest realm=\"realm1\", nonce=\"f2a3f18799759d4f1a1c068b92b573cb\", qop=auth";
final Header authChallenge2 = new BasicHeader(AUTH.WWW_AUTH, challenge2);
authscheme.processChallenge(authChallenge2);
final AuthChallenge authChallenge2 = parse(challenge2);
authscheme.processChallenge(ChallengeType.TARGET, authChallenge2);
final Header authResponse3 = authscheme.authenticate(cred, request, context);
final Map<String, String> table3 = parseAuthResponse(authResponse3);
Assert.assertEquals("00000003", table3.get("nc"));
final String challenge3 = "Digest realm=\"realm1\", nonce=\"e273f1776275974f1a120d8b92c5b3cb\", qop=auth";
final Header authChallenge3 = new BasicHeader(AUTH.WWW_AUTH, challenge3);
authscheme.processChallenge(authChallenge3);
final AuthChallenge authChallenge3 = parse(challenge3);
authscheme.processChallenge(ChallengeType.TARGET, authChallenge3);
final Header authResponse4 = authscheme.authenticate(cred, request, context);
final Map<String, String> table4 = parseAuthResponse(authResponse4);
Assert.assertEquals("00000001", table4.get("nc"));
@ -463,12 +455,12 @@ public class TestDigestScheme {
public void testDigestMD5SessA1AndCnonceConsistency() throws Exception {
final String challenge1 = "Digest qop=\"auth\", algorithm=MD5-sess, nonce=\"1234567890abcdef\", " +
"charset=utf-8, realm=\"subnet.domain.com\"";
final Header authChallenge1 = new BasicHeader(AUTH.WWW_AUTH, challenge1);
final AuthChallenge authChallenge1 = parse(challenge1);
final HttpRequest request = new BasicHttpRequest("GET", "/");
final Credentials cred = new UsernamePasswordCredentials("username","password");
final HttpContext context = new BasicHttpContext();
final DigestScheme authscheme = new DigestScheme();
authscheme.processChallenge(authChallenge1);
authscheme.processChallenge(ChallengeType.TARGET, authChallenge1);
final Header authResponse1 = authscheme.authenticate(cred, request, context);
final Map<String, String> table1 = parseAuthResponse(authResponse1);
Assert.assertEquals("00000001", table1.get("nc"));
@ -486,8 +478,8 @@ public class TestDigestScheme {
final String challenge2 = "Digest qop=\"auth\", algorithm=MD5-sess, nonce=\"1234567890abcdef\", " +
"charset=utf-8, realm=\"subnet.domain.com\"";
final Header authChallenge2 = new BasicHeader(AUTH.WWW_AUTH, challenge2);
authscheme.processChallenge(authChallenge2);
final AuthChallenge authChallenge2 = parse(challenge2);
authscheme.processChallenge(ChallengeType.TARGET, authChallenge2);
final Header authResponse3 = authscheme.authenticate(cred, request, context);
final Map<String, String> table3 = parseAuthResponse(authResponse3);
Assert.assertEquals("00000003", table3.get("nc"));
@ -500,8 +492,8 @@ public class TestDigestScheme {
final String challenge3 = "Digest qop=\"auth\", algorithm=MD5-sess, nonce=\"fedcba0987654321\", " +
"charset=utf-8, realm=\"subnet.domain.com\"";
final Header authChallenge3 = new BasicHeader(AUTH.WWW_AUTH, challenge3);
authscheme.processChallenge(authChallenge3);
final AuthChallenge authChallenge3 = parse(challenge3);
authscheme.processChallenge(ChallengeType.TARGET, authChallenge3);
final Header authResponse4 = authscheme.authenticate(cred, request, context);
final Map<String, String> table4 = parseAuthResponse(authResponse4);
Assert.assertEquals("00000001", table4.get("nc"));
@ -543,13 +535,13 @@ public class TestDigestScheme {
public void testDigestAuthenticationQopAuthInt() throws Exception {
final String challenge = "Digest realm=\"realm1\", nonce=\"f2a3f18799759d4f1a1c068b92b573cb\", " +
"qop=\"auth,auth-int\"";
final Header authChallenge = new BasicHeader(AUTH.WWW_AUTH, challenge);
final AuthChallenge authChallenge = parse(challenge);
final HttpEntityEnclosingRequest request = new BasicHttpEntityEnclosingRequest("Post", "/");
request.setEntity(new StringEntity("abc\u00e4\u00f6\u00fcabc", HTTP.DEF_CONTENT_CHARSET));
final Credentials cred = new UsernamePasswordCredentials("username","password");
final DigestScheme authscheme = new DigestScheme();
final HttpContext context = new BasicHttpContext();
authscheme.processChallenge(authChallenge);
authscheme.processChallenge(ChallengeType.TARGET, authChallenge);
final Header authResponse = authscheme.authenticate(cred, request, context);
Assert.assertEquals("Post:/:acd2b59cd01c7737d8069015584c6cac", authscheme.getA2());
@ -566,12 +558,12 @@ public class TestDigestScheme {
public void testDigestAuthenticationQopAuthIntNullEntity() throws Exception {
final String challenge = "Digest realm=\"realm1\", nonce=\"f2a3f18799759d4f1a1c068b92b573cb\", " +
"qop=\"auth,auth-int\"";
final Header authChallenge = new BasicHeader(AUTH.WWW_AUTH, challenge);
final AuthChallenge authChallenge = parse(challenge);
final HttpRequest request = new BasicHttpEntityEnclosingRequest("Post", "/");
final Credentials cred = new UsernamePasswordCredentials("username","password");
final DigestScheme authscheme = new DigestScheme();
final HttpContext context = new BasicHttpContext();
authscheme.processChallenge(authChallenge);
authscheme.processChallenge(ChallengeType.TARGET, authChallenge);
final Header authResponse = authscheme.authenticate(cred, request, context);
Assert.assertEquals("Post:/:d41d8cd98f00b204e9800998ecf8427e", authscheme.getA2());
@ -588,13 +580,13 @@ public class TestDigestScheme {
public void testDigestAuthenticationQopAuthOrAuthIntNonRepeatableEntity() throws Exception {
final String challenge = "Digest realm=\"realm1\", nonce=\"f2a3f18799759d4f1a1c068b92b573cb\", " +
"qop=\"auth,auth-int\"";
final Header authChallenge = new BasicHeader(AUTH.WWW_AUTH, challenge);
final AuthChallenge authChallenge = parse(challenge);
final HttpEntityEnclosingRequest request = new BasicHttpEntityEnclosingRequest("Post", "/");
request.setEntity(new InputStreamEntity(new ByteArrayInputStream(new byte[] {'a'}), -1));
final Credentials cred = new UsernamePasswordCredentials("username","password");
final DigestScheme authscheme = new DigestScheme();
final HttpContext context = new BasicHttpContext();
authscheme.processChallenge(authChallenge);
authscheme.processChallenge(ChallengeType.TARGET, authChallenge);
final Header authResponse = authscheme.authenticate(cred, request, context);
Assert.assertEquals("Post:/", authscheme.getA2());
@ -612,12 +604,12 @@ public class TestDigestScheme {
final String challenge = "Digest Realm=\"-\", " +
"nonce=\"YjYuNGYyYmJhMzUuY2I5ZDhlZDE5M2ZlZDM 1Mjk3NGJkNTIyYjgyNTcwMjQ=\", " +
"opaque=\"98700A3D9CE17065E2246B41035C6609\", qop=\"auth\"";
final Header authChallenge = new BasicHeader(AUTH.PROXY_AUTH, challenge);
final AuthChallenge authChallenge = parse(challenge);
final HttpRequest request = new BasicHttpRequest("GET", "/");
final Credentials cred = new UsernamePasswordCredentials("username","password");
final DigestScheme authscheme = new DigestScheme();
final HttpContext context = new BasicHttpContext();
authscheme.processChallenge(authChallenge);
authscheme.processChallenge(ChallengeType.TARGET, authChallenge);
Assert.assertEquals("-", authscheme.getRealm());
authscheme.authenticate(cred, request, context);
@ -627,13 +619,13 @@ public class TestDigestScheme {
public void testDigestAuthenticationQopIntOnlyNonRepeatableEntity() throws Exception {
final String challenge = "Digest realm=\"realm1\", nonce=\"f2a3f18799759d4f1a1c068b92b573cb\", " +
"qop=\"auth-int\"";
final Header authChallenge = new BasicHeader(AUTH.WWW_AUTH, challenge);
final AuthChallenge authChallenge = parse(challenge);
final HttpEntityEnclosingRequest request = new BasicHttpEntityEnclosingRequest("Post", "/");
request.setEntity(new InputStreamEntity(new ByteArrayInputStream(new byte[] {'a'}), -1));
final Credentials cred = new UsernamePasswordCredentials("username","password");
final DigestScheme authscheme = new DigestScheme();
final HttpContext context = new BasicHttpContext();
authscheme.processChallenge(authChallenge);
authscheme.processChallenge(ChallengeType.TARGET, authChallenge);
authscheme.authenticate(cred, request, context);
}
@ -641,9 +633,9 @@ public class TestDigestScheme {
public void testSerialization() throws Exception {
final String challenge = "Digest realm=\"realm1\", nonce=\"f2a3f18799759d4f1a1c068b92b573cb\", " +
"qop=\"auth,auth-int\"";
final Header authChallenge = new BasicHeader(AUTH.WWW_AUTH, challenge);
final AuthChallenge authChallenge = parse(challenge);
final DigestScheme digestScheme = new DigestScheme();
digestScheme.processChallenge(authChallenge);
digestScheme.processChallenge(ChallengeType.TARGET, authChallenge);
final ByteArrayOutputStream buffer = new ByteArrayOutputStream();
final ObjectOutputStream out = new ObjectOutputStream(buffer);

View File

@ -26,11 +26,10 @@
*/
package org.apache.http.impl.auth;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Queue;
import org.apache.http.Header;
import org.apache.http.HttpHeaders;
import org.apache.http.HttpHost;
import org.apache.http.HttpRequest;
import org.apache.http.HttpResponse;
@ -44,15 +43,14 @@ import org.apache.http.auth.AuthSchemeProvider;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.AuthState;
import org.apache.http.auth.AuthenticationException;
import org.apache.http.auth.ChallengeType;
import org.apache.http.auth.Credentials;
import org.apache.http.auth.MalformedChallengeException;
import org.apache.http.client.AuthCache;
import org.apache.http.client.AuthenticationStrategy;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.config.Lookup;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.client.TargetAuthenticationStrategy;
import org.apache.http.impl.client.DefaultAuthenticationStrategy;
import org.apache.http.message.BasicHeader;
import org.apache.http.message.BasicHttpRequest;
import org.apache.http.message.BasicHttpResponse;
@ -67,7 +65,6 @@ import org.mockito.Mockito;
@SuppressWarnings({"boxing","static-access"})
public class TestHttpAuthenticator {
private AuthenticationStrategy defltAuthStrategy;
private AuthState authState;
private AuthScheme authScheme;
private HttpContext context;
@ -80,7 +77,6 @@ public class TestHttpAuthenticator {
@Before
public void setUp() throws Exception {
this.defltAuthStrategy = Mockito.mock(AuthenticationStrategy.class);
this.authState = new AuthState();
this.authScheme = Mockito.mock(AuthScheme.class);
Mockito.when(this.authScheme.getSchemeName()).thenReturn("Basic");
@ -103,86 +99,61 @@ public class TestHttpAuthenticator {
}
@Test
public void testAuthenticationRequested() throws Exception {
public void testUpdateAuthState() throws Exception {
final HttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SC_UNAUTHORIZED, "UNAUTHORIZED");
Mockito.when(this.defltAuthStrategy.isAuthenticationRequested(
Mockito.any(HttpHost.class),
Mockito.any(HttpResponse.class),
Mockito.any(HttpContext.class))).thenReturn(Boolean.TRUE);
Assert.assertTrue(this.httpAuthenticator.isAuthenticationRequested(
this.defaultHost, response, this.defltAuthStrategy, this.authState, this.context));
Mockito.verify(this.defltAuthStrategy).isAuthenticationRequested(this.defaultHost, response, this.context);
response.setHeader(HttpHeaders.WWW_AUTHENTICATE, "Basic realm=test");
Assert.assertTrue(this.httpAuthenticator.updateAuthState(
this.defaultHost, ChallengeType.TARGET, response, this.authState, this.context));
Mockito.verifyZeroInteractions(this.authCache);
}
@Test
public void testAuthenticationRequestedAfterSuccess() throws Exception {
final HttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SC_UNAUTHORIZED, "UNAUTHORIZED");
Mockito.when(this.defltAuthStrategy.isAuthenticationRequested(
Mockito.any(HttpHost.class),
Mockito.any(HttpResponse.class),
Mockito.any(HttpContext.class))).thenReturn(Boolean.TRUE);
response.setHeader(HttpHeaders.WWW_AUTHENTICATE, "Basic realm=test");
this.authState.update(this.authScheme, this.credentials);
this.authState.setState(AuthProtocolState.SUCCESS);
Assert.assertTrue(this.httpAuthenticator.isAuthenticationRequested(
this.defaultHost, response, this.defltAuthStrategy, this.authState, this.context));
Assert.assertTrue(this.httpAuthenticator.updateAuthState(
this.defaultHost, ChallengeType.TARGET, response, this.authState, this.context));
Mockito.verify(this.defltAuthStrategy).isAuthenticationRequested(this.defaultHost, response, this.context);
Mockito.verify(this.defltAuthStrategy).authFailed(this.defaultHost, this.authScheme, this.context);
Mockito.verify(this.authCache).remove(this.defaultHost);
}
@Test
public void testAuthenticationNotRequestedUnchallenged() throws Exception {
final HttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SC_OK, "OK");
Mockito.when(this.defltAuthStrategy.isAuthenticationRequested(
Mockito.any(HttpHost.class),
Mockito.any(HttpResponse.class),
Mockito.any(HttpContext.class))).thenReturn(Boolean.FALSE);
Assert.assertFalse(this.httpAuthenticator.isAuthenticationRequested(
this.defaultHost, response, this.defltAuthStrategy, this.authState, this.context));
Assert.assertFalse(this.httpAuthenticator.updateAuthState(
this.defaultHost, ChallengeType.TARGET, response, this.authState, this.context));
Assert.assertEquals(AuthProtocolState.UNCHALLENGED, this.authState.getState());
Mockito.verify(this.defltAuthStrategy).isAuthenticationRequested(this.defaultHost, response, this.context);
}
@Test
public void testAuthenticationNotRequestedSuccess1() throws Exception {
final HttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SC_OK, "OK");
Mockito.when(this.defltAuthStrategy.isAuthenticationRequested(
Mockito.any(HttpHost.class),
Mockito.any(HttpResponse.class),
Mockito.any(HttpContext.class))).thenReturn(Boolean.FALSE);
this.authState.update(this.authScheme, this.credentials);
this.authState.setState(AuthProtocolState.CHALLENGED);
Assert.assertFalse(this.httpAuthenticator.isAuthenticationRequested(
this.defaultHost, response, this.defltAuthStrategy, this.authState, this.context));
Assert.assertFalse(this.httpAuthenticator.updateAuthState(
this.defaultHost, ChallengeType.TARGET, response, this.authState, this.context));
Assert.assertEquals(AuthProtocolState.SUCCESS, this.authState.getState());
Mockito.verify(this.defltAuthStrategy).isAuthenticationRequested(this.defaultHost, response, this.context);
Mockito.verify(this.defltAuthStrategy).authSucceeded(this.defaultHost, this.authScheme, this.context);
Mockito.verify(this.authCache).put(this.defaultHost, this.authScheme);
}
@Test
public void testAuthenticationNotRequestedSuccess2() throws Exception {
final HttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SC_OK, "OK");
Mockito.when(this.defltAuthStrategy.isAuthenticationRequested(
Mockito.any(HttpHost.class),
Mockito.any(HttpResponse.class),
Mockito.any(HttpContext.class))).thenReturn(Boolean.FALSE);
this.authState.update(this.authScheme, this.credentials);
this.authState.setState(AuthProtocolState.HANDSHAKE);
Assert.assertFalse(this.httpAuthenticator.isAuthenticationRequested(
this.defaultHost, response, this.defltAuthStrategy, this.authState, this.context));
Assert.assertFalse(this.httpAuthenticator.updateAuthState(
this.defaultHost, ChallengeType.TARGET, response, this.authState, this.context));
Assert.assertEquals(AuthProtocolState.SUCCESS, this.authState.getState());
Mockito.verify(this.defltAuthStrategy).isAuthenticationRequested(this.defaultHost, response, this.context);
Mockito.verify(this.defltAuthStrategy).authSucceeded(this.defaultHost, this.authScheme, this.context);
Mockito.verify(this.authCache).put(this.defaultHost, this.authScheme);
}
@Test
@ -193,10 +164,10 @@ public class TestHttpAuthenticator {
response.addHeader(new BasicHeader(AUTH.WWW_AUTH, "Digest realm=\"realm1\", nonce=\"1234\""));
response.addHeader(new BasicHeader(AUTH.WWW_AUTH, "whatever realm=\"realm1\", stuff=\"1234\""));
final TargetAuthenticationStrategy authStrategy = new TargetAuthenticationStrategy();
final DefaultAuthenticationStrategy authStrategy = new DefaultAuthenticationStrategy();
Assert.assertTrue(this.httpAuthenticator.handleAuthChallenge(host,
response, authStrategy, this.authState, this.context));
Assert.assertTrue(this.httpAuthenticator.handleAuthChallenge(
host,ChallengeType.TARGET, response, authStrategy, this.authState, this.context));
Assert.assertEquals(AuthProtocolState.CHALLENGED, this.authState.getState());
final Queue<AuthOption> options = this.authState.getAuthOptions();
@ -215,13 +186,10 @@ public class TestHttpAuthenticator {
final HttpHost host = new HttpHost("somehost", 80);
final HttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SC_UNAUTHORIZED, "UNAUTHORIZED");
Mockito.when(this.defltAuthStrategy.getChallenges(
Mockito.any(HttpHost.class),
Mockito.any(HttpResponse.class),
Mockito.any(HttpContext.class))).thenReturn(new HashMap<String, Header>());
final DefaultAuthenticationStrategy authStrategy = new DefaultAuthenticationStrategy();
Assert.assertFalse(this.httpAuthenticator.handleAuthChallenge(host,
response, this.defltAuthStrategy, this.authState, this.context));
Assert.assertFalse(this.httpAuthenticator.handleAuthChallenge(
host, ChallengeType.TARGET, response, authStrategy, this.authState, this.context));
}
@Test
@ -231,10 +199,10 @@ public class TestHttpAuthenticator {
response.addHeader(new BasicHeader(AUTH.WWW_AUTH, "This realm=\"test\""));
response.addHeader(new BasicHeader(AUTH.WWW_AUTH, "That realm=\"realm1\", nonce=\"1234\""));
final TargetAuthenticationStrategy authStrategy = new TargetAuthenticationStrategy();
final DefaultAuthenticationStrategy authStrategy = new DefaultAuthenticationStrategy();
Assert.assertFalse(this.httpAuthenticator.handleAuthChallenge(host,
response, authStrategy, this.authState, this.context));
Assert.assertFalse(this.httpAuthenticator.handleAuthChallenge(
host, ChallengeType.TARGET, response, authStrategy, this.authState, this.context));
}
@Test
@ -246,10 +214,10 @@ public class TestHttpAuthenticator {
this.credentialsProvider.clear();
final TargetAuthenticationStrategy authStrategy = new TargetAuthenticationStrategy();
final DefaultAuthenticationStrategy authStrategy = new DefaultAuthenticationStrategy();
Assert.assertFalse(this.httpAuthenticator.handleAuthChallenge(host,
response, authStrategy, this.authState, this.context));
Assert.assertFalse(this.httpAuthenticator.handleAuthChallenge(
host, ChallengeType.TARGET, response, authStrategy, this.authState, this.context));
}
@Test
@ -262,10 +230,10 @@ public class TestHttpAuthenticator {
this.authState.setState(AuthProtocolState.CHALLENGED);
this.authState.update(this.authScheme, this.credentials);
final TargetAuthenticationStrategy authStrategy = new TargetAuthenticationStrategy();
final DefaultAuthenticationStrategy authStrategy = new DefaultAuthenticationStrategy();
Assert.assertFalse(this.httpAuthenticator.handleAuthChallenge(host,
response, authStrategy, this.authState, this.context));
Assert.assertFalse(this.httpAuthenticator.handleAuthChallenge(
host, ChallengeType.TARGET, response, authStrategy, this.authState, this.context));
Assert.assertEquals(AuthProtocolState.FAILURE, this.authState.getState());
@ -281,10 +249,10 @@ public class TestHttpAuthenticator {
this.authState.setState(AuthProtocolState.FAILURE);
final TargetAuthenticationStrategy authStrategy = new TargetAuthenticationStrategy();
final DefaultAuthenticationStrategy authStrategy = new DefaultAuthenticationStrategy();
Assert.assertFalse(this.httpAuthenticator.handleAuthChallenge(host,
response, authStrategy, this.authState, this.context));
Assert.assertFalse(this.httpAuthenticator.handleAuthChallenge(
host, ChallengeType.TARGET, response, authStrategy, this.authState, this.context));
Assert.assertEquals(AuthProtocolState.FAILURE, this.authState.getState());
}
@ -297,13 +265,13 @@ public class TestHttpAuthenticator {
response.addHeader(new BasicHeader(AUTH.WWW_AUTH, "Digest realm=\"realm1\", nonce=\"1234\""));
response.addHeader(new BasicHeader(AUTH.WWW_AUTH, "whatever realm=\"realm1\", stuff=\"1234\""));
final TargetAuthenticationStrategy authStrategy = new TargetAuthenticationStrategy();
final DefaultAuthenticationStrategy authStrategy = new DefaultAuthenticationStrategy();
this.authState.setState(AuthProtocolState.CHALLENGED);
this.authState.update(new BasicScheme(), this.credentials);
Assert.assertFalse(this.httpAuthenticator.handleAuthChallenge(host,
response, authStrategy, this.authState, this.context));
Assert.assertFalse(this.httpAuthenticator.handleAuthChallenge(
host, ChallengeType.TARGET, response, authStrategy, this.authState, this.context));
Assert.assertEquals(AuthProtocolState.FAILURE, this.authState.getState());
Assert.assertNull(this.authState.getCredentials());
}
@ -316,13 +284,13 @@ public class TestHttpAuthenticator {
response.addHeader(new BasicHeader(AUTH.WWW_AUTH, "Digest realm=\"realm1\", stale=true, nonce=\"1234\""));
response.addHeader(new BasicHeader(AUTH.WWW_AUTH, "whatever realm=\"realm1\", stuff=\"1234\""));
final TargetAuthenticationStrategy authStrategy = new TargetAuthenticationStrategy();
final DefaultAuthenticationStrategy authStrategy = new DefaultAuthenticationStrategy();
this.authState.setState(AuthProtocolState.CHALLENGED);
this.authState.update(new DigestScheme(), this.credentials);
Assert.assertTrue(this.httpAuthenticator.handleAuthChallenge(host,
response, authStrategy, this.authState, this.context));
Assert.assertTrue(this.httpAuthenticator.handleAuthChallenge(
host, ChallengeType.TARGET, response, authStrategy, this.authState, this.context));
Assert.assertEquals(AuthProtocolState.HANDSHAKE, this.authState.getState());
}
@ -334,13 +302,13 @@ public class TestHttpAuthenticator {
response.addHeader(new BasicHeader(AUTH.WWW_AUTH, "Digest realm=\"realm1\", nonce=\"1234\""));
response.addHeader(new BasicHeader(AUTH.WWW_AUTH, "whatever realm=\"realm1\", stuff=\"1234\""));
final TargetAuthenticationStrategy authStrategy = new TargetAuthenticationStrategy();
final DefaultAuthenticationStrategy authStrategy = new DefaultAuthenticationStrategy();
this.authState.setState(AuthProtocolState.CHALLENGED);
this.authState.update(new BasicScheme(), this.credentials);
Assert.assertTrue(this.httpAuthenticator.handleAuthChallenge(host,
response, authStrategy, this.authState, this.context));
Assert.assertTrue(this.httpAuthenticator.handleAuthChallenge(
host, ChallengeType.TARGET, response, authStrategy, this.authState, this.context));
Assert.assertEquals(AuthProtocolState.CHALLENGED, this.authState.getState());
final Queue<AuthOption> options = this.authState.getAuthOptions();
@ -355,16 +323,14 @@ public class TestHttpAuthenticator {
public void testAuthenticationException() throws Exception {
final HttpHost host = new HttpHost("somehost", 80);
final HttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SC_UNAUTHORIZED, "UNAUTHORIZED");
response.addHeader(new BasicHeader(AUTH.WWW_AUTH, "blah blah blah"));
this.authState.setState(AuthProtocolState.CHALLENGED);
Mockito.doThrow(new MalformedChallengeException()).when(this.defltAuthStrategy).getChallenges(
Mockito.any(HttpHost.class),
Mockito.any(HttpResponse.class),
Mockito.any(HttpContext.class));
final DefaultAuthenticationStrategy authStrategy = new DefaultAuthenticationStrategy();
Assert.assertFalse(this.httpAuthenticator.handleAuthChallenge(host,
response, this.defltAuthStrategy, this.authState, this.context));
Assert.assertFalse(this.httpAuthenticator.handleAuthChallenge(
host, ChallengeType.TARGET, response, authStrategy, this.authState, this.context));
Assert.assertEquals(AuthProtocolState.UNCHALLENGED, this.authState.getState());
Assert.assertNull(this.authState.getAuthScheme());

View File

@ -0,0 +1,87 @@
/*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
*/
package org.apache.http.impl.auth;
import org.apache.http.Header;
import org.apache.http.HttpRequest;
import org.apache.http.auth.AuthChallenge;
import org.apache.http.auth.AuthenticationException;
import org.apache.http.auth.ChallengeType;
import org.apache.http.auth.Credentials;
import org.apache.http.auth.MalformedChallengeException;
import org.apache.http.protocol.HttpContext;
import org.junit.Assert;
import org.junit.Test;
public class TestNonStandardHttpScheme {
static class TestAuthScheme extends NonStandardAuthScheme {
@Override
public void processChallenge(
final ChallengeType challengeType, final AuthChallenge authChallenge) throws MalformedChallengeException {
update(challengeType, authChallenge);
}
@Override
public Header authenticate(
final Credentials credentials,
final HttpRequest request,
final HttpContext context) throws AuthenticationException {
return null;
}
@Override
public String getSchemeName() {
return "test";
}
@Override
public boolean isComplete() {
return false;
}
@Override
public boolean isConnectionBased() {
return false;
}
}
@Test
public void testProcessChallenge() throws Exception {
final TestAuthScheme authscheme = new TestAuthScheme();
authscheme.processChallenge(ChallengeType.TARGET, new AuthChallenge("Test", "this_and_that", null));
Assert.assertEquals("test", authscheme.getSchemeName());
Assert.assertEquals("test(TARGET) this_and_that", authscheme.toString());
Assert.assertEquals("this_and_that", authscheme.getChallenge());
}
}

View File

@ -1,175 +0,0 @@
/*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
*/
package org.apache.http.impl.auth;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.nio.charset.Charset;
import org.apache.http.Consts;
import org.apache.http.Header;
import org.apache.http.HttpRequest;
import org.apache.http.auth.AUTH;
import org.apache.http.auth.AuthenticationException;
import org.apache.http.auth.Credentials;
import org.apache.http.auth.MalformedChallengeException;
import org.apache.http.message.BasicHeader;
import org.apache.http.message.BufferedHeader;
import org.apache.http.protocol.HttpContext;
import org.apache.http.util.CharArrayBuffer;
import org.junit.Assert;
import org.junit.Test;
public class TestRFC2617Scheme {
static class TestAuthScheme extends RFC2617Scheme {
private static final long serialVersionUID = 1L;
public TestAuthScheme() {
super();
}
public TestAuthScheme(final Charset charset) {
super(charset);
}
@Override
public Header authenticate(
final Credentials credentials,
final HttpRequest request,
final HttpContext context) throws AuthenticationException {
return null;
}
@Override
public String getSchemeName() {
return "test";
}
@Override
public boolean isComplete() {
return false;
}
@Override
public boolean isConnectionBased() {
return false;
}
}
@Test
public void testProcessChallenge() throws Exception {
final TestAuthScheme authscheme = new TestAuthScheme();
final Header header = new BasicHeader(
AUTH.WWW_AUTH,
"Test realm=\"realm1\", test, test1 = stuff, test2 = \"stuff, stuff\", test3=\"crap");
authscheme.processChallenge(header);
Assert.assertEquals("test", authscheme.getSchemeName());
Assert.assertEquals("TEST", authscheme.toString());
Assert.assertEquals("realm1", authscheme.getParameter("realm"));
Assert.assertEquals(null, authscheme.getParameter("test"));
Assert.assertEquals("stuff", authscheme.getParameter("test1"));
Assert.assertEquals("stuff, stuff", authscheme.getParameter("test2"));
Assert.assertEquals("crap", authscheme.getParameter("test3"));
Assert.assertEquals(null, authscheme.getParameter(null));
}
@Test
public void testProcessChallengeWithLotsOfBlanks() throws Exception {
final TestAuthScheme authscheme = new TestAuthScheme();
final CharArrayBuffer buffer = new CharArrayBuffer(32);
buffer.append(" WWW-Authenticate: Test realm=\"realm1\"");
final Header header = new BufferedHeader(buffer);
authscheme.processChallenge(header);
Assert.assertEquals("test", authscheme.getSchemeName());
Assert.assertEquals("realm1", authscheme.getParameter("realm"));
}
@Test
public void testNullHeader() throws Exception {
final TestAuthScheme authscheme = new TestAuthScheme();
try {
authscheme.processChallenge(null);
Assert.fail("IllegalArgumentException should have been thrown");
} catch (final IllegalArgumentException ex) {
}
}
@Test(expected=MalformedChallengeException.class)
public void testInvalidHeader() throws Exception {
final TestAuthScheme authscheme = new TestAuthScheme();
final Header header = new BasicHeader("whatever", "Test realm=\"realm1\"");
authscheme.processChallenge(header);
}
@Test(expected=MalformedChallengeException.class)
public void testInvalidSchemeName() throws Exception {
final TestAuthScheme authscheme = new TestAuthScheme();
final Header header = new BasicHeader(AUTH.WWW_AUTH, "Not-a-Test realm=\"realm1\"");
authscheme.processChallenge(header);
}
@Test(expected=MalformedChallengeException.class)
public void testInvalidHeaderValue() throws Exception {
final TestAuthScheme authscheme = new TestAuthScheme();
final Header header = new BasicHeader("whatever", "whatever");
authscheme.processChallenge(header);
}
@Test
public void testSerialization() throws Exception {
final Header challenge = new BasicHeader(AUTH.WWW_AUTH, "test realm=\"test\", blah=blah, yada=\"yada yada\"");
final TestAuthScheme testScheme = new TestAuthScheme(Consts.ISO_8859_1);
testScheme.processChallenge(challenge);
final ByteArrayOutputStream buffer = new ByteArrayOutputStream();
final ObjectOutputStream out = new ObjectOutputStream(buffer);
out.writeObject(testScheme);
out.flush();
final byte[] raw = buffer.toByteArray();
final ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(raw));
final TestAuthScheme authScheme = (TestAuthScheme) in.readObject();
Assert.assertEquals(Consts.ISO_8859_1, authScheme.getCredentialsCharset());
Assert.assertEquals("test", authScheme.getParameter("realm"));
Assert.assertEquals("blah", authScheme.getParameter("blah"));
Assert.assertEquals("yada yada", authScheme.getParameter("yada"));
}
}

View File

@ -0,0 +1,95 @@
/*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
*/
package org.apache.http.impl.auth;
import java.util.Arrays;
import org.apache.http.Header;
import org.apache.http.HttpRequest;
import org.apache.http.auth.AuthChallenge;
import org.apache.http.auth.AuthenticationException;
import org.apache.http.auth.ChallengeType;
import org.apache.http.auth.Credentials;
import org.apache.http.auth.MalformedChallengeException;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.protocol.HttpContext;
import org.junit.Assert;
import org.junit.Test;
public class TestStandardHttpScheme {
static class TestAuthScheme extends StandardAuthScheme {
private static final long serialVersionUID = 1L;
@Override
public void processChallenge(
final ChallengeType challengeType, final AuthChallenge authChallenge) throws MalformedChallengeException {
update(challengeType, authChallenge);
}
@Override
public Header authenticate(
final Credentials credentials,
final HttpRequest request,
final HttpContext context) throws AuthenticationException {
return null;
}
@Override
public String getSchemeName() {
return "test";
}
@Override
public boolean isComplete() {
return false;
}
@Override
public boolean isConnectionBased() {
return false;
}
}
@Test
public void testProcessChallenge() throws Exception {
final TestAuthScheme authscheme = new TestAuthScheme();
authscheme.processChallenge(ChallengeType.TARGET, new AuthChallenge("Test", null, Arrays.asList(
new BasicNameValuePair("realm", "realm1"), new BasicNameValuePair("this", "blah"))));
Assert.assertEquals("test", authscheme.getSchemeName());
Assert.assertEquals("test(TARGET) {realm=realm1, this=blah}", authscheme.toString());
Assert.assertEquals("realm1", authscheme.getParameter("realm"));
Assert.assertEquals(null, authscheme.getParameter("test"));
Assert.assertEquals("blah", authscheme.getParameter("this"));
}
}

View File

@ -27,23 +27,19 @@
package org.apache.http.impl.client;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Queue;
import org.apache.http.Header;
import org.apache.http.HttpHost;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.HttpVersion;
import org.apache.http.auth.AUTH;
import org.apache.http.auth.AuthChallenge;
import org.apache.http.auth.AuthOption;
import org.apache.http.auth.AuthScheme;
import org.apache.http.auth.AuthSchemeProvider;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.ChallengeType;
import org.apache.http.auth.CredentialsProvider;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.AuthCache;
import org.apache.http.client.config.AuthSchemes;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.protocol.HttpClientContext;
@ -53,98 +49,38 @@ import org.apache.http.impl.auth.BasicScheme;
import org.apache.http.impl.auth.BasicSchemeFactory;
import org.apache.http.impl.auth.DigestScheme;
import org.apache.http.impl.auth.DigestSchemeFactory;
import org.apache.http.message.BasicHeader;
import org.apache.http.message.BasicHttpResponse;
import org.apache.http.message.BasicNameValuePair;
import org.junit.Assert;
import org.junit.Test;
import org.mockito.Mockito;
/**
* Simple tests for {@link AuthenticationStrategyImpl}.
* Simple tests for {@link DefaultAuthenticationStrategy}.
*/
@SuppressWarnings("boxing") // test code
public class TestAuthenticationStrategy {
@Test(expected=IllegalArgumentException.class)
public void testIsAuthenticationRequestedInvalidInput() throws Exception {
final TargetAuthenticationStrategy authStrategy = new TargetAuthenticationStrategy();
final HttpHost host = new HttpHost("localhost", 80);
final HttpClientContext context = HttpClientContext.create();
authStrategy.isAuthenticationRequested(host, null, context);
}
@Test
public void testTargetAuthRequested() throws Exception {
final TargetAuthenticationStrategy authStrategy = new TargetAuthenticationStrategy();
final HttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SC_UNAUTHORIZED, "UNAUTHORIZED");
final HttpHost host = new HttpHost("localhost", 80);
final HttpClientContext context = HttpClientContext.create();
Assert.assertTrue(authStrategy.isAuthenticationRequested(host, response, context));
}
@Test
public void testProxyAuthRequested() throws Exception {
final ProxyAuthenticationStrategy authStrategy = new ProxyAuthenticationStrategy();
final HttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SC_PROXY_AUTHENTICATION_REQUIRED, "UNAUTHORIZED");
final HttpHost host = new HttpHost("localhost", 80);
final HttpClientContext context = HttpClientContext.create();
Assert.assertTrue(authStrategy.isAuthenticationRequested(host, response, context));
}
@Test(expected=IllegalArgumentException.class)
public void testGetChallengesInvalidInput() throws Exception {
final TargetAuthenticationStrategy authStrategy = new TargetAuthenticationStrategy();
final HttpHost host = new HttpHost("localhost", 80);
final HttpClientContext context = HttpClientContext.create();
authStrategy.getChallenges(host, null, context);
}
@Test
public void testGetChallenges() throws Exception {
final TargetAuthenticationStrategy authStrategy = new TargetAuthenticationStrategy();
final HttpClientContext context = HttpClientContext.create();
final HttpHost host = new HttpHost("localhost", 80);
final HttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SC_UNAUTHORIZED, "UNAUTHORIZED");
final Header h1 = new BasicHeader(AUTH.WWW_AUTH, " Basic realm=\"test\"");
final Header h2 = new BasicHeader(AUTH.WWW_AUTH, "\t\tDigest realm=\"realm1\", nonce=\"1234\"");
final Header h3 = new BasicHeader(AUTH.WWW_AUTH, "WhatEver realm=\"realm1\", stuff=\"1234\"");
response.addHeader(h1);
response.addHeader(h2);
response.addHeader(h3);
final Map<String, Header> challenges = authStrategy.getChallenges(host, response, context);
Assert.assertNotNull(challenges);
Assert.assertEquals(3, challenges.size());
Assert.assertSame(h1, challenges.get("basic"));
Assert.assertSame(h2, challenges.get("digest"));
Assert.assertSame(h3, challenges.get("whatever"));
}
@Test
public void testSelectInvalidInput() throws Exception {
final TargetAuthenticationStrategy authStrategy = new TargetAuthenticationStrategy();
final Map<String, Header> challenges = new HashMap<>();
final HttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SC_UNAUTHORIZED, "UNAUTHORIZED");
final DefaultAuthenticationStrategy authStrategy = new DefaultAuthenticationStrategy();
final HttpHost authhost = new HttpHost("locahost", 80);
final HttpClientContext context = HttpClientContext.create();
try {
authStrategy.select(null, authhost, response, context);
authStrategy.select(null, authhost, Collections.<String, AuthChallenge>emptyMap(), context);
Assert.fail("IllegalArgumentException expected");
} catch (final IllegalArgumentException ex) {
}
try {
authStrategy.select(challenges, null, response, context);
authStrategy.select(ChallengeType.TARGET, null, Collections.<String, AuthChallenge>emptyMap(), context);
Assert.fail("IllegalArgumentException expected");
} catch (final IllegalArgumentException ex) {
}
try {
authStrategy.select(challenges, authhost, null, context);
authStrategy.select(ChallengeType.TARGET, authhost, null, context);
Assert.fail("IllegalArgumentException expected");
} catch (final IllegalArgumentException ex) {
}
try {
authStrategy.select(challenges, authhost, response, null);
authStrategy.select(ChallengeType.TARGET, authhost, Collections.<String, AuthChallenge>emptyMap(), null);
Assert.fail("IllegalArgumentException expected");
} catch (final IllegalArgumentException ex) {
}
@ -152,51 +88,54 @@ public class TestAuthenticationStrategy {
@Test
public void testSelectNoSchemeRegistry() throws Exception {
final TargetAuthenticationStrategy authStrategy = new TargetAuthenticationStrategy();
final HttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SC_UNAUTHORIZED, "UNAUTHORIZED");
final DefaultAuthenticationStrategy authStrategy = new DefaultAuthenticationStrategy();
final HttpHost authhost = new HttpHost("locahost", 80);
final HttpClientContext context = HttpClientContext.create();
final Map<String, Header> challenges = new HashMap<>();
challenges.put("basic", new BasicHeader(AUTH.WWW_AUTH, "Basic realm=\"test\""));
challenges.put("digest", new BasicHeader(AUTH.WWW_AUTH, "Digest realm=\"realm1\", nonce=\"1234\""));
final Map<String, AuthChallenge> challenges = new HashMap<>();
challenges.put("basic", new AuthChallenge("Basic",
new BasicNameValuePair("realm", "test")));
challenges.put("digest", new AuthChallenge("Digest",
new BasicNameValuePair("realm", "test"), new BasicNameValuePair("nonce", "1234")));
final Queue<AuthOption> options = authStrategy.select(challenges, authhost, response, context);
final Queue<AuthOption> options = authStrategy.select(ChallengeType.TARGET, authhost, challenges, context);
Assert.assertNotNull(options);
Assert.assertEquals(0, options.size());
}
@Test
public void testSelectNoCredentialsProvider() throws Exception {
final TargetAuthenticationStrategy authStrategy = new TargetAuthenticationStrategy();
final HttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SC_UNAUTHORIZED, "UNAUTHORIZED");
final DefaultAuthenticationStrategy authStrategy = new DefaultAuthenticationStrategy();
final HttpHost authhost = new HttpHost("locahost", 80);
final HttpClientContext context = HttpClientContext.create();
final Map<String, Header> challenges = new HashMap<>();
challenges.put("basic", new BasicHeader(AUTH.WWW_AUTH, "Basic realm=\"test\""));
challenges.put("digest", new BasicHeader(AUTH.WWW_AUTH, "Digest realm=\"realm1\", nonce=\"1234\""));
final Map<String, AuthChallenge> challenges = new HashMap<>();
challenges.put("basic", new AuthChallenge("Basic",
new BasicNameValuePair("realm", "test")));
challenges.put("digest", new AuthChallenge("Digest",
new BasicNameValuePair("realm", "test"), new BasicNameValuePair("nonce", "1234")));
final Registry<AuthSchemeProvider> authSchemeRegistry = RegistryBuilder.<AuthSchemeProvider>create()
.register("basic", new BasicSchemeFactory())
.register("digest", new DigestSchemeFactory()).build();
context.setAuthSchemeRegistry(authSchemeRegistry);
final Queue<AuthOption> options = authStrategy.select(challenges, authhost, response, context);
final Queue<AuthOption> options = authStrategy.select(ChallengeType.TARGET, authhost, challenges, context);
Assert.assertNotNull(options);
Assert.assertEquals(0, options.size());
}
@Test
public void testNoCredentials() throws Exception {
final TargetAuthenticationStrategy authStrategy = new TargetAuthenticationStrategy();
final HttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SC_UNAUTHORIZED, "UNAUTHORIZED");
final DefaultAuthenticationStrategy authStrategy = new DefaultAuthenticationStrategy();
final HttpHost authhost = new HttpHost("locahost", 80);
final HttpClientContext context = HttpClientContext.create();
final Map<String, Header> challenges = new HashMap<>();
challenges.put("basic", new BasicHeader(AUTH.WWW_AUTH, "Basic realm=\"realm1\""));
challenges.put("digest", new BasicHeader(AUTH.WWW_AUTH, "Digest realm=\"realm2\", nonce=\"1234\""));
final Map<String, AuthChallenge> challenges = new HashMap<>();
challenges.put("basic", new AuthChallenge("Basic",
new BasicNameValuePair("realm", "realm1")));
challenges.put("digest", new AuthChallenge("Digest",
new BasicNameValuePair("realm", "realm2"), new BasicNameValuePair("nonce", "1234")));
final Registry<AuthSchemeProvider> authSchemeRegistry = RegistryBuilder.<AuthSchemeProvider>create()
.register("basic", new BasicSchemeFactory())
@ -206,21 +145,22 @@ public class TestAuthenticationStrategy {
final CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
context.setCredentialsProvider(credentialsProvider);
final Queue<AuthOption> options = authStrategy.select(challenges, authhost, response, context);
final Queue<AuthOption> options = authStrategy.select(ChallengeType.TARGET, authhost, challenges, context);
Assert.assertNotNull(options);
Assert.assertEquals(0, options.size());
}
@Test
public void testCredentialsFound() throws Exception {
final TargetAuthenticationStrategy authStrategy = new TargetAuthenticationStrategy();
final HttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SC_UNAUTHORIZED, "UNAUTHORIZED");
final DefaultAuthenticationStrategy authStrategy = new DefaultAuthenticationStrategy();
final HttpHost authhost = new HttpHost("somehost", 80);
final HttpClientContext context = HttpClientContext.create();
final Map<String, Header> challenges = new HashMap<>();
challenges.put("basic", new BasicHeader(AUTH.WWW_AUTH, "Basic realm=\"realm1\""));
challenges.put("digest", new BasicHeader(AUTH.WWW_AUTH, "Digest realm=\"realm2\", nonce=\"1234\""));
final Map<String, AuthChallenge> challenges = new HashMap<>();
challenges.put("basic", new AuthChallenge("Basic",
new BasicNameValuePair("realm", "realm1")));
challenges.put("digest", new AuthChallenge("Digest",
new BasicNameValuePair("realm", "realm2"), new BasicNameValuePair("nonce", "1234")));
final Registry<AuthSchemeProvider> authSchemeRegistry = RegistryBuilder.<AuthSchemeProvider>create()
.register("basic", new BasicSchemeFactory())
@ -232,7 +172,7 @@ public class TestAuthenticationStrategy {
new UsernamePasswordCredentials("user", "pwd"));
context.setCredentialsProvider(credentialsProvider);
final Queue<AuthOption> options = authStrategy.select(challenges, authhost, response, context);
final Queue<AuthOption> options = authStrategy.select(ChallengeType.TARGET, authhost, challenges, context);
Assert.assertNotNull(options);
Assert.assertEquals(1, options.size());
final AuthOption option = options.remove();
@ -241,15 +181,17 @@ public class TestAuthenticationStrategy {
@Test
public void testUnsupportedScheme() throws Exception {
final TargetAuthenticationStrategy authStrategy = new TargetAuthenticationStrategy();
final HttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SC_UNAUTHORIZED, "UNAUTHORIZED");
final DefaultAuthenticationStrategy authStrategy = new DefaultAuthenticationStrategy();
final HttpHost authhost = new HttpHost("somehost", 80);
final HttpClientContext context = HttpClientContext.create();
final Map<String, Header> challenges = new HashMap<>();
challenges.put("basic", new BasicHeader(AUTH.WWW_AUTH, "Basic realm=\"realm1\""));
challenges.put("digest", new BasicHeader(AUTH.WWW_AUTH, "Digest realm=\"realm2\", nonce=\"1234\""));
challenges.put("whatever", new BasicHeader(AUTH.WWW_AUTH, "Whatever realm=\"realm3\""));
final Map<String, AuthChallenge> challenges = new HashMap<>();
challenges.put("basic", new AuthChallenge("Basic",
new BasicNameValuePair("realm", "realm1")));
challenges.put("digest", new AuthChallenge("Digest",
new BasicNameValuePair("realm", "realm2"), new BasicNameValuePair("nonce", "1234")));
challenges.put("whatever", new AuthChallenge("Whatever",
new BasicNameValuePair("realm", "realm3")));
final Registry<AuthSchemeProvider> authSchemeRegistry = RegistryBuilder.<AuthSchemeProvider>create()
.register("basic", new BasicSchemeFactory())
@ -261,7 +203,7 @@ public class TestAuthenticationStrategy {
new UsernamePasswordCredentials("user", "pwd"));
context.setCredentialsProvider(credentialsProvider);
final Queue<AuthOption> options = authStrategy.select(challenges, authhost, response, context);
final Queue<AuthOption> options = authStrategy.select(ChallengeType.TARGET, authhost, challenges, context);
Assert.assertNotNull(options);
Assert.assertEquals(2, options.size());
final AuthOption option1 = options.remove();
@ -272,8 +214,7 @@ public class TestAuthenticationStrategy {
@Test
public void testCustomAuthPreference() throws Exception {
final TargetAuthenticationStrategy authStrategy = new TargetAuthenticationStrategy();
final HttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SC_UNAUTHORIZED, "UNAUTHORIZED");
final DefaultAuthenticationStrategy authStrategy = new DefaultAuthenticationStrategy();
final RequestConfig config = RequestConfig.custom()
.setTargetPreferredAuthSchemes(Arrays.asList(AuthSchemes.BASIC))
.build();
@ -281,9 +222,11 @@ public class TestAuthenticationStrategy {
final HttpHost authhost = new HttpHost("somehost", 80);
final HttpClientContext context = HttpClientContext.create();
final Map<String, Header> challenges = new HashMap<>();
challenges.put("basic", new BasicHeader(AUTH.WWW_AUTH, "Basic realm=\"realm1\""));
challenges.put("digest", new BasicHeader(AUTH.WWW_AUTH, "Digest realm=\"realm2\", nonce=\"1234\""));
final Map<String, AuthChallenge> challenges = new HashMap<>();
challenges.put("basic", new AuthChallenge("Basic",
new BasicNameValuePair("realm", "realm1")));
challenges.put("digest", new AuthChallenge("Digest",
new BasicNameValuePair("realm", "realm2"), new BasicNameValuePair("nonce", "1234")));
final Registry<AuthSchemeProvider> authSchemeRegistry = RegistryBuilder.<AuthSchemeProvider>create()
.register("basic", new BasicSchemeFactory())
@ -296,143 +239,11 @@ public class TestAuthenticationStrategy {
new UsernamePasswordCredentials("user", "pwd"));
context.setCredentialsProvider(credentialsProvider);
final Queue<AuthOption> options = authStrategy.select(challenges, authhost, response, context);
final Queue<AuthOption> options = authStrategy.select(ChallengeType.TARGET, authhost, challenges, context);
Assert.assertNotNull(options);
Assert.assertEquals(1, options.size());
final AuthOption option1 = options.remove();
Assert.assertTrue(option1.getAuthScheme() instanceof BasicScheme);
}
@Test
public void testAuthSucceededInvalidInput() throws Exception {
final TargetAuthenticationStrategy authStrategy = new TargetAuthenticationStrategy();
final HttpHost authhost = new HttpHost("locahost", 80);
final BasicScheme authScheme = new BasicScheme();
final HttpClientContext context = HttpClientContext.create();
try {
authStrategy.authSucceeded(null, authScheme, context);
Assert.fail("IllegalArgumentException expected");
} catch (final IllegalArgumentException ex) {
}
try {
authStrategy.authSucceeded(authhost, null, context);
Assert.fail("IllegalArgumentException expected");
} catch (final IllegalArgumentException ex) {
}
try {
authStrategy.authSucceeded(authhost, authScheme, null);
Assert.fail("IllegalArgumentException expected");
} catch (final IllegalArgumentException ex) {
}
}
@Test
public void testAuthSucceeded() throws Exception {
final TargetAuthenticationStrategy authStrategy = new TargetAuthenticationStrategy();
final HttpHost authhost = new HttpHost("somehost", 80);
final BasicScheme authScheme = new BasicScheme();
authScheme.processChallenge(new BasicHeader(AUTH.WWW_AUTH, "Basic realm=test"));
final AuthCache authCache = Mockito.mock(AuthCache.class);
final HttpClientContext context = HttpClientContext.create();
context.setAuthCache(authCache);
authStrategy.authSucceeded(authhost, authScheme, context);
Mockito.verify(authCache).put(authhost, authScheme);
}
@Test
public void testAuthSucceededNoCache() throws Exception {
final TargetAuthenticationStrategy authStrategy = new TargetAuthenticationStrategy();
final HttpHost authhost = new HttpHost("somehost", 80);
final BasicScheme authScheme = new BasicScheme();
authScheme.processChallenge(new BasicHeader(AUTH.WWW_AUTH, "Basic realm=test"));
final HttpClientContext context = HttpClientContext.create();
context.setAuthCache(null);
authStrategy.authSucceeded(authhost, authScheme, context);
final AuthCache authCache = context.getAuthCache();
Assert.assertNotNull(authCache);
}
@Test
public void testAuthScemeNotCompleted() throws Exception {
final TargetAuthenticationStrategy authStrategy = new TargetAuthenticationStrategy();
final HttpHost authhost = new HttpHost("somehost", 80);
final BasicScheme authScheme = new BasicScheme();
final AuthCache authCache = Mockito.mock(AuthCache.class);
final HttpClientContext context = HttpClientContext.create();
context.setAuthCache(authCache);
authStrategy.authSucceeded(authhost, authScheme, context);
Mockito.verify(authCache, Mockito.never()).put(authhost, authScheme);
}
@Test
public void testAuthScemeNonCacheable() throws Exception {
final TargetAuthenticationStrategy authStrategy = new TargetAuthenticationStrategy();
final HttpHost authhost = new HttpHost("somehost", 80);
final AuthScheme authScheme = Mockito.mock(AuthScheme.class);
Mockito.when(authScheme.isComplete()).thenReturn(true);
Mockito.when(authScheme.getSchemeName()).thenReturn("whatever");
final AuthCache authCache = Mockito.mock(AuthCache.class);
final HttpClientContext context = HttpClientContext.create();
context.setAuthCache(authCache);
authStrategy.authSucceeded(authhost, authScheme, context);
Mockito.verify(authCache, Mockito.never()).put(authhost, authScheme);
}
@Test
public void testAuthFailedInvalidInput() throws Exception {
final TargetAuthenticationStrategy authStrategy = new TargetAuthenticationStrategy();
final HttpHost authhost = new HttpHost("locahost", 80);
final BasicScheme authScheme = new BasicScheme();
final HttpClientContext context = HttpClientContext.create();
try {
authStrategy.authFailed(null, authScheme, context);
Assert.fail("IllegalArgumentException expected");
} catch (final IllegalArgumentException ex) {
}
try {
authStrategy.authFailed(authhost, authScheme, null);
Assert.fail("IllegalArgumentException expected");
} catch (final IllegalArgumentException ex) {
}
}
@Test
public void testAuthFailed() throws Exception {
final TargetAuthenticationStrategy authStrategy = new TargetAuthenticationStrategy();
final HttpHost authhost = new HttpHost("somehost", 80);
final BasicScheme authScheme = new BasicScheme();
authScheme.processChallenge(new BasicHeader(AUTH.WWW_AUTH, "Basic realm=test"));
final AuthCache authCache = Mockito.mock(AuthCache.class);
final HttpClientContext context = HttpClientContext.create();
context.setAuthCache(authCache);
authStrategy.authFailed(authhost, authScheme, context);
Mockito.verify(authCache).remove(authhost);
}
@Test
public void testAuthFailedNoCache() throws Exception {
final TargetAuthenticationStrategy authStrategy = new TargetAuthenticationStrategy();
final HttpHost authhost = new HttpHost("somehost", 80);
final BasicScheme authScheme = new BasicScheme();
final HttpClientContext context = HttpClientContext.create();
context.setAuthCache(null);
authStrategy.authFailed(authhost, authScheme, context);
}
}

View File

@ -28,6 +28,8 @@ package org.apache.http.impl.client.integration;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.Map;
import java.util.Queue;
import java.util.concurrent.atomic.AtomicLong;
import org.apache.http.Consts;
@ -39,9 +41,13 @@ import org.apache.http.HttpRequest;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.auth.AUTH;
import org.apache.http.auth.AuthChallenge;
import org.apache.http.auth.AuthOption;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.ChallengeType;
import org.apache.http.auth.Credentials;
import org.apache.http.auth.CredentialsProvider;
import org.apache.http.auth.MalformedChallengeException;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.AuthCache;
import org.apache.http.client.ClientProtocolException;
@ -56,7 +62,7 @@ import org.apache.http.entity.StringEntity;
import org.apache.http.impl.auth.BasicScheme;
import org.apache.http.impl.client.BasicAuthCache;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.client.TargetAuthenticationStrategy;
import org.apache.http.impl.client.DefaultAuthenticationStrategy;
import org.apache.http.localserver.BasicAuthTokenExtractor;
import org.apache.http.localserver.LocalServerTestBase;
import org.apache.http.localserver.RequestBasicAuth;
@ -342,7 +348,7 @@ public class TestClientAuthentication extends LocalServerTestBase {
}
}
static class TestTargetAuthenticationStrategy extends TargetAuthenticationStrategy {
static class TestTargetAuthenticationStrategy extends DefaultAuthenticationStrategy {
private final AtomicLong count;
@ -352,15 +358,14 @@ public class TestClientAuthentication extends LocalServerTestBase {
}
@Override
public boolean isAuthenticationRequested(
public Queue<AuthOption> select(
final ChallengeType challengeType,
final HttpHost host,
final HttpResponse response,
final HttpContext context) {
final boolean res = super.isAuthenticationRequested(host, response, context);
if (res == true) {
this.count.incrementAndGet();
}
return res;
final Map<String, AuthChallenge> challenges,
final HttpContext context) throws MalformedChallengeException {
final Queue<AuthOption> authOptions = super.select(challengeType, host, challenges, context);
this.count.incrementAndGet();
return authOptions;
}
public long getCount() {

View File

@ -46,6 +46,7 @@ import org.apache.http.auth.Credentials;
import org.apache.http.auth.CredentialsProvider;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.config.Registry;
@ -53,7 +54,6 @@ import org.apache.http.config.RegistryBuilder;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.auth.BasicScheme;
import org.apache.http.impl.auth.BasicSchemeFactory;
import org.apache.http.impl.client.TargetAuthenticationStrategy;
import org.apache.http.localserver.LocalServerTestBase;
import org.apache.http.localserver.RequestBasicAuth;
import org.apache.http.protocol.HttpContext;
@ -162,15 +162,6 @@ public class TestClientReauthentication extends LocalServerTestBase {
};
final TargetAuthenticationStrategy myAuthStrategy = new TargetAuthenticationStrategy() {
@Override
protected boolean isCachable(final AuthScheme authScheme) {
return "MyBasic".equalsIgnoreCase(authScheme.getSchemeName());
}
};
final TestCredentialsProvider credsProvider = new TestCredentialsProvider(
new UsernamePasswordCredentials("test", "test"));
@ -182,7 +173,6 @@ public class TestClientReauthentication extends LocalServerTestBase {
.build();
this.httpclient = this.clientBuilder
.setDefaultAuthSchemeRegistry(authSchemeRegistry)
.setTargetAuthenticationStrategy(myAuthStrategy)
.setDefaultCredentialsProvider(credsProvider)
.build();
@ -192,11 +182,12 @@ public class TestClientReauthentication extends LocalServerTestBase {
for (int i = 0; i < 10; i++) {
final HttpGet httpget = new HttpGet("/");
httpget.setConfig(config);
final HttpResponse response = this.httpclient.execute(target, httpget, context);
final HttpEntity entity = response.getEntity();
Assert.assertEquals(HttpStatus.SC_OK, response.getStatusLine().getStatusCode());
Assert.assertNotNull(entity);
EntityUtils.consume(entity);
try (final CloseableHttpResponse response = this.httpclient.execute(target, httpget, context)) {
final HttpEntity entity = response.getEntity();
Assert.assertEquals(HttpStatus.SC_OK, response.getStatusLine().getStatusCode());
Assert.assertNotNull(entity);
EntityUtils.consume(entity);
}
}
}

View File

@ -32,25 +32,26 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.InterruptedIOException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Collections;
import java.util.LinkedList;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import org.apache.http.ConnectionReuseStrategy;
import org.apache.http.Header;
import org.apache.http.HttpClientConnection;
import org.apache.http.HttpEntityEnclosingRequest;
import org.apache.http.HttpException;
import org.apache.http.HttpHeaders;
import org.apache.http.HttpHost;
import org.apache.http.HttpRequest;
import org.apache.http.HttpResponse;
import org.apache.http.HttpVersion;
import org.apache.http.auth.AUTH;
import org.apache.http.auth.AuthChallenge;
import org.apache.http.auth.AuthOption;
import org.apache.http.auth.AuthProtocolState;
import org.apache.http.auth.AuthState;
import org.apache.http.auth.ChallengeType;
import org.apache.http.auth.NTCredentials;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.AuthenticationStrategy;
@ -74,7 +75,6 @@ import org.apache.http.entity.StringEntity;
import org.apache.http.impl.auth.BasicScheme;
import org.apache.http.impl.auth.NTLMScheme;
import org.apache.http.impl.conn.ConnectionShutdownException;
import org.apache.http.message.BasicHeader;
import org.apache.http.message.BasicHttpResponse;
import org.apache.http.protocol.HttpContext;
import org.apache.http.protocol.HttpProcessor;
@ -132,39 +132,6 @@ public class TestMainClientExec {
Mockito.<HttpRoute>any(), Mockito.any())).thenReturn(connRequest);
Mockito.when(connRequest.get(
Mockito.anyLong(), Mockito.<TimeUnit>any())).thenReturn(managedConn);
final Map<String, Header> challenges = new HashMap<>();
challenges.put("basic", new BasicHeader(AUTH.WWW_AUTH, "Basic realm=test"));
final AuthOption authOption = new AuthOption(
new BasicScheme(), new UsernamePasswordCredentials("user:pass"));
Mockito.when(targetAuthStrategy.getChallenges(
Mockito.eq(target),
Mockito.<HttpResponse>any(),
Mockito.<HttpClientContext>any())).thenReturn(challenges);
Mockito.when(targetAuthStrategy.getChallenges(
Mockito.eq(target),
Mockito.<HttpResponse>any(),
Mockito.<HttpClientContext>any())).thenReturn(challenges);
Mockito.when(targetAuthStrategy.select(
Mockito.same(challenges),
Mockito.eq(target),
Mockito.<HttpResponse>any(),
Mockito.<HttpClientContext>any())).thenReturn(
new LinkedList<>(Arrays.asList(authOption)));
Mockito.when(proxyAuthStrategy.getChallenges(
Mockito.eq(proxy),
Mockito.<HttpResponse>any(),
Mockito.<HttpClientContext>any())).thenReturn(challenges);
Mockito.when(proxyAuthStrategy.getChallenges(
Mockito.eq(proxy),
Mockito.<HttpResponse>any(),
Mockito.<HttpClientContext>any())).thenReturn(challenges);
Mockito.when(proxyAuthStrategy.select(
Mockito.same(challenges),
Mockito.eq(proxy),
Mockito.<HttpResponse>any(),
Mockito.<HttpClientContext>any())).thenReturn(
new LinkedList<>(Arrays.asList(authOption)));
}
@Test
@ -418,6 +385,7 @@ public class TestMainClientExec {
final HttpClientContext context = new HttpClientContext();
final HttpRequestWrapper request = HttpRequestWrapper.wrap(new HttpGet("http://bar/test"));
final HttpResponse response1 = new BasicHttpResponse(HttpVersion.HTTP_1_1, 401, "Huh?");
response1.setHeader(HttpHeaders.WWW_AUTHENTICATE, "Basic realm=test");
final InputStream instream1 = Mockito.spy(new ByteArrayInputStream(new byte[] {1, 2, 3}));
response1.setEntity(EntityBuilder.create()
.setStream(instream1)
@ -437,10 +405,14 @@ public class TestMainClientExec {
Mockito.when(reuseStrategy.keepAlive(
Mockito.<HttpResponse>any(),
Mockito.<HttpClientContext>any())).thenReturn(Boolean.TRUE);
Mockito.when(targetAuthStrategy.isAuthenticationRequested(
Mockito.when(targetAuthStrategy.select(
Mockito.eq(ChallengeType.TARGET),
Mockito.eq(target),
Mockito.same(response1),
Mockito.<HttpClientContext>any())).thenReturn(Boolean.TRUE);
Mockito.<Map<String, AuthChallenge>>any(),
Mockito.<HttpClientContext>any())).thenReturn(new LinkedList<>(
Collections.singleton(new AuthOption(
new BasicScheme(),
new UsernamePasswordCredentials("user", "pass")))));
final CloseableHttpResponse finalResponse = mainClientExec.execute(
route, request, context, execAware);
@ -457,6 +429,7 @@ public class TestMainClientExec {
final HttpRoute route = new HttpRoute(target);
final HttpRequestWrapper request = HttpRequestWrapper.wrap(new HttpGet("http://bar/test"));
final HttpResponse response1 = new BasicHttpResponse(HttpVersion.HTTP_1_1, 401, "Huh?");
response1.setHeader(HttpHeaders.WWW_AUTHENTICATE, "Basic realm=test");
final InputStream instream1 = Mockito.spy(new ByteArrayInputStream(new byte[] {1, 2, 3}));
response1.setEntity(EntityBuilder.create()
.setStream(instream1)
@ -483,10 +456,15 @@ public class TestMainClientExec {
Mockito.when(reuseStrategy.keepAlive(
Mockito.<HttpResponse>any(),
Mockito.<HttpClientContext>any())).thenReturn(Boolean.FALSE);
Mockito.when(targetAuthStrategy.isAuthenticationRequested(
final AuthOption authOption = new AuthOption(
new BasicScheme(), new UsernamePasswordCredentials("user:pass"));
Mockito.when(targetAuthStrategy.select(
Mockito.eq(ChallengeType.TARGET),
Mockito.eq(target),
Mockito.same(response1),
Mockito.<HttpClientContext>any())).thenReturn(Boolean.TRUE);
Mockito.<Map<String, AuthChallenge>>any(),
Mockito.<HttpClientContext>any())).thenReturn(
new LinkedList<>(Arrays.asList(authOption)));
final CloseableHttpResponse finalResponse = mainClientExec.execute(
route, request, context, execAware);
@ -512,6 +490,7 @@ public class TestMainClientExec {
final HttpRequestWrapper request = HttpRequestWrapper.wrap(post);
final HttpResponse response1 = new BasicHttpResponse(HttpVersion.HTTP_1_1, 401, "Huh?");
response1.setHeader(HttpHeaders.WWW_AUTHENTICATE, "Basic realm=test");
final InputStream instream1 = new ByteArrayInputStream(new byte[] {1, 2, 3});
response1.setEntity(EntityBuilder.create()
.setStream(instream1)
@ -536,10 +515,15 @@ public class TestMainClientExec {
Mockito.when(reuseStrategy.keepAlive(
Mockito.<HttpResponse>any(),
Mockito.<HttpClientContext>any())).thenReturn(Boolean.TRUE);
Mockito.when(targetAuthStrategy.isAuthenticationRequested(
final AuthOption authOption = new AuthOption(
new BasicScheme(), new UsernamePasswordCredentials("user:pass"));
Mockito.when(targetAuthStrategy.select(
Mockito.eq(ChallengeType.TARGET),
Mockito.eq(target),
Mockito.same(response1),
Mockito.<HttpClientContext>any())).thenReturn(Boolean.TRUE);
Mockito.<Map<String, AuthChallenge>>any(),
Mockito.<HttpClientContext>any())).thenReturn(
new LinkedList<>(Arrays.asList(authOption)));
mainClientExec.execute(route, request, context, execAware);
}
@ -732,7 +716,8 @@ public class TestMainClientExec {
final HttpRoute route = new HttpRoute(target, null, proxy, true);
final HttpClientContext context = new HttpClientContext();
final HttpRequestWrapper request = HttpRequestWrapper.wrap(new HttpGet("http://bar/test"));
final HttpResponse response1 = new BasicHttpResponse(HttpVersion.HTTP_1_1, 401, "Huh?");
final HttpResponse response1 = new BasicHttpResponse(HttpVersion.HTTP_1_1, 407, "Huh?");
response1.setHeader(HttpHeaders.PROXY_AUTHENTICATE, "Basic realm=test");
final InputStream instream1 = Mockito.spy(new ByteArrayInputStream(new byte[] {1, 2, 3}));
response1.setEntity(EntityBuilder.create()
.setStream(instream1)
@ -740,10 +725,6 @@ public class TestMainClientExec {
final HttpResponse response2 = new BasicHttpResponse(HttpVersion.HTTP_1_1, 200, "OK");
Mockito.when(managedConn.isOpen()).thenReturn(Boolean.TRUE);
Mockito.when(proxyAuthStrategy.isAuthenticationRequested(
Mockito.eq(proxy),
Mockito.same(response1),
Mockito.<HttpClientContext>any())).thenReturn(Boolean.TRUE);
Mockito.when(reuseStrategy.keepAlive(
Mockito.<HttpResponse>any(),
Mockito.<HttpClientContext>any())).thenReturn(Boolean.TRUE);
@ -752,6 +733,15 @@ public class TestMainClientExec {
Mockito.<HttpClientConnection>any(),
Mockito.<HttpClientContext>any())).thenReturn(response1, response2);
final AuthOption authOption = new AuthOption(
new BasicScheme(), new UsernamePasswordCredentials("user:pass"));
Mockito.when(proxyAuthStrategy.select(
Mockito.eq(ChallengeType.PROXY),
Mockito.eq(proxy),
Mockito.<Map<String, AuthChallenge>>any(),
Mockito.<HttpClientContext>any())).thenReturn(
new LinkedList<>(Arrays.asList(authOption)));
mainClientExec.establishRoute(authState, managedConn, route, request, context);
Mockito.verify(connManager).connect(managedConn, route, 0, context);
@ -765,7 +755,8 @@ public class TestMainClientExec {
final HttpRoute route = new HttpRoute(target, null, proxy, true);
final HttpClientContext context = new HttpClientContext();
final HttpRequestWrapper request = HttpRequestWrapper.wrap(new HttpGet("http://bar/test"));
final HttpResponse response1 = new BasicHttpResponse(HttpVersion.HTTP_1_1, 401, "Huh?");
final HttpResponse response1 = new BasicHttpResponse(HttpVersion.HTTP_1_1, 407, "Huh?");
response1.setHeader(HttpHeaders.PROXY_AUTHENTICATE, "Basic realm=test");
final InputStream instream1 = Mockito.spy(new ByteArrayInputStream(new byte[] {1, 2, 3}));
response1.setEntity(EntityBuilder.create()
.setStream(instream1)
@ -773,10 +764,6 @@ public class TestMainClientExec {
final HttpResponse response2 = new BasicHttpResponse(HttpVersion.HTTP_1_1, 200, "OK");
Mockito.when(managedConn.isOpen()).thenReturn(Boolean.TRUE);
Mockito.when(proxyAuthStrategy.isAuthenticationRequested(
Mockito.eq(proxy),
Mockito.same(response1),
Mockito.<HttpClientContext>any())).thenReturn(Boolean.TRUE);
Mockito.when(reuseStrategy.keepAlive(
Mockito.<HttpResponse>any(),
Mockito.<HttpClientContext>any())).thenReturn(Boolean.FALSE);
@ -785,6 +772,15 @@ public class TestMainClientExec {
Mockito.<HttpClientConnection>any(),
Mockito.<HttpClientContext>any())).thenReturn(response1, response2);
final AuthOption authOption = new AuthOption(
new BasicScheme(), new UsernamePasswordCredentials("user:pass"));
Mockito.when(proxyAuthStrategy.select(
Mockito.eq(ChallengeType.PROXY),
Mockito.eq(proxy),
Mockito.<Map<String, AuthChallenge>>any(),
Mockito.<HttpClientContext>any())).thenReturn(
new LinkedList<>(Arrays.asList(authOption)));
mainClientExec.establishRoute(authState, managedConn, route, request, context);
Mockito.verify(connManager).connect(managedConn, route, 0, context);