diff --git a/httpclient/src/examples/org/apache/http/examples/client/ClientInteractiveAuthentication.java b/httpclient/src/examples/org/apache/http/examples/client/ClientInteractiveAuthentication.java index 5294e263e..5e6d4c11e 100644 --- a/httpclient/src/examples/org/apache/http/examples/client/ClientInteractiveAuthentication.java +++ b/httpclient/src/examples/org/apache/http/examples/client/ClientInteractiveAuthentication.java @@ -29,8 +29,10 @@ import java.io.BufferedReader; import java.io.InputStreamReader; import org.apache.http.HttpEntity; +import org.apache.http.HttpHost; import org.apache.http.HttpResponse; import org.apache.http.HttpStatus; +import org.apache.http.auth.AuthScheme; import org.apache.http.auth.AuthScope; import org.apache.http.auth.AuthState; import org.apache.http.auth.Credentials; @@ -39,6 +41,7 @@ import org.apache.http.client.methods.HttpGet; import org.apache.http.client.protocol.ClientContext; import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.protocol.BasicHttpContext; +import org.apache.http.protocol.ExecutionContext; import org.apache.http.protocol.HttpContext; import org.apache.http.util.EntityUtils; @@ -71,22 +74,23 @@ public class ClientInteractiveAuthentication { int sc = response.getStatusLine().getStatusCode(); AuthState authState = null; + HttpHost authhost = null; if (sc == HttpStatus.SC_UNAUTHORIZED) { // Target host authentication required authState = (AuthState) localContext.getAttribute(ClientContext.TARGET_AUTH_STATE); + authhost = (HttpHost) localContext.getAttribute(ExecutionContext.HTTP_TARGET_HOST); } if (sc == HttpStatus.SC_PROXY_AUTHENTICATION_REQUIRED) { // Proxy authentication required authState = (AuthState) localContext.getAttribute(ClientContext.PROXY_AUTH_STATE); + authhost = (HttpHost) localContext.getAttribute(ExecutionContext.HTTP_PROXY_HOST); } if (authState != null) { System.out.println("----------------------------------------"); - AuthScope authScope = authState.getAuthScope(); - System.out.println("Please provide credentials"); - System.out.println(" Host: " + authScope.getHost() + ":" + authScope.getPort()); - System.out.println(" Realm: " + authScope.getRealm()); - + AuthScheme authscheme = authState.getAuthScheme(); + System.out.println("Please provide credentials for " + + authscheme.getRealm() + "@" + authhost.toHostString()); BufferedReader console = new BufferedReader(new InputStreamReader(System.in)); @@ -97,7 +101,7 @@ public class ClientInteractiveAuthentication { if (user != null && user.length() > 0) { Credentials creds = new UsernamePasswordCredentials(user, password); - httpclient.getCredentialsProvider().setCredentials(authScope, creds); + httpclient.getCredentialsProvider().setCredentials(new AuthScope(authhost), creds); trying = true; } else { trying = false; diff --git a/httpclient/src/main/java/org/apache/http/auth/AuthChallengeState.java b/httpclient/src/main/java/org/apache/http/auth/AuthChallengeState.java new file mode 100644 index 000000000..3fee7db10 --- /dev/null +++ b/httpclient/src/main/java/org/apache/http/auth/AuthChallengeState.java @@ -0,0 +1,33 @@ +/* + * ==================================================================== + * + * 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 + * . + * + */ + +package org.apache.http.auth; + +public enum AuthChallengeState { + + UNCHALLENGED, CHALLENGED, FAILURE, SUCCESS + +} diff --git a/httpclient/src/main/java/org/apache/http/auth/AuthState.java b/httpclient/src/main/java/org/apache/http/auth/AuthState.java index 2c16dd46d..613587c93 100644 --- a/httpclient/src/main/java/org/apache/http/auth/AuthState.java +++ b/httpclient/src/main/java/org/apache/http/auth/AuthState.java @@ -30,15 +30,16 @@ import org.apache.http.annotation.NotThreadSafe; /** - * This class provides detailed information about the state of the - * authentication process. - * + * This class provides detailed information about the state of the authentication process. * * @since 4.0 */ @NotThreadSafe public class AuthState { + /** Actual state of authentication process */ + private AuthChallengeState challengeState; + /** Actual authentication scheme */ private AuthScheme authScheme; @@ -54,12 +55,14 @@ public class AuthState { */ public AuthState() { super(); + this.challengeState = AuthChallengeState.UNCHALLENGED; } /** * Invalidates the authentication state by resetting its parameters. */ public void invalidate() { + this.challengeState = AuthChallengeState.UNCHALLENGED; this.authScheme = null; this.authScope = null; this.credentials = null; @@ -92,6 +95,19 @@ public class AuthState { return this.authScheme; } + /** + * @since 4.2 + */ + public AuthChallengeState getChallengeState() { + return this.challengeState; + } + + /** + * @since 4.2 + */ + public void setChallengeState(final AuthChallengeState state) { + this.challengeState = state != null ? state : AuthChallengeState.UNCHALLENGED; + } /** * Returns user {@link Credentials} selected for authentication if available @@ -102,7 +118,6 @@ public class AuthState { return this.credentials; } - /** * Sets user {@link Credentials} to be used for authentication * @@ -112,34 +127,40 @@ public class AuthState { this.credentials = credentials; } - /** * Returns actual {@link AuthScope} if available * * @return actual authentication scope if available, null challenges = authHandler.getChallenges(response, context); + if (challenges.isEmpty()) { + this.log.debug("Response contains no authentication challenges"); + return false; + } AuthScheme authScheme = authState.getAuthScheme(); if (authScheme == null) { // Authentication not attempted before @@ -86,6 +108,7 @@ public class HttpAuthenticator { id = authScheme.getSchemeName(); challenge = challenges.get(id.toLowerCase(Locale.US)); } + authState.setChallengeState(AuthChallengeState.CHALLENGED); authScheme.processChallenge(challenge); this.log.debug("Authorization challenge processed"); @@ -111,21 +134,23 @@ public class HttpAuthenticator { } else { if (authScheme.isComplete()) { this.log.debug("Authentication failed"); + authState.setChallengeState(AuthChallengeState.FAILURE); creds = null; } } - authState.setAuthScope(authScope); authState.setCredentials(creds); return creds != null; } catch (MalformedChallengeException ex) { if (this.log.isWarnEnabled()) { this.log.warn("Malformed challenge: " + ex.getMessage()); } + authState.invalidate(); return false; } catch (AuthenticationException ex) { if (this.log.isWarnEnabled()) { this.log.warn("Authentication error: " + ex.getMessage()); } + authState.invalidate(); return false; } } diff --git a/httpclient/src/test/java/org/apache/http/client/protocol/TestRequestProxyAuthentication.java b/httpclient/src/test/java/org/apache/http/client/protocol/TestRequestProxyAuthentication.java index b255df15d..d9a51ea65 100644 --- a/httpclient/src/test/java/org/apache/http/client/protocol/TestRequestProxyAuthentication.java +++ b/httpclient/src/test/java/org/apache/http/client/protocol/TestRequestProxyAuthentication.java @@ -33,7 +33,7 @@ import org.apache.http.HttpHost; import org.apache.http.HttpRequest; import org.apache.http.HttpRequestInterceptor; import org.apache.http.auth.AUTH; -import org.apache.http.auth.AuthScope; +import org.apache.http.auth.AuthChallengeState; import org.apache.http.auth.AuthState; import org.apache.http.auth.Credentials; import org.apache.http.auth.UsernamePasswordCredentials; @@ -81,13 +81,11 @@ public class TestRequestProxyAuthentication { BasicScheme authscheme = new BasicScheme(); Credentials creds = new UsernamePasswordCredentials("user", "secret"); - AuthScope authscope = new AuthScope("localhost", 8080, "auth-realm", "http"); BasicHeader challenge = new BasicHeader(AUTH.PROXY_AUTH, "BASIC realm=auth-realm"); authscheme.processChallenge(challenge); AuthState authstate = new AuthState(); authstate.setAuthScheme(authscheme); - authstate.setAuthScope(authscope); authstate.setCredentials(creds); context.setAttribute(ExecutionContext.HTTP_CONNECTION, conn); @@ -115,14 +113,12 @@ public class TestRequestProxyAuthentication { BasicScheme authscheme = new BasicScheme(); Credentials creds = new UsernamePasswordCredentials("user", "secret"); - AuthScope authscope = new AuthScope("localhost", 8080, "auth-realm", "http"); BasicHeader challenge = new BasicHeader(AUTH.PROXY_AUTH, "BASIC realm=auth-realm"); authscheme.processChallenge(challenge); AuthState authstate = new AuthState(); authstate.setAuthScheme(authscheme); - authstate.setAuthScope(authscope); authstate.setCredentials(creds); context.setAttribute(ExecutionContext.HTTP_CONNECTION, conn); @@ -150,14 +146,12 @@ public class TestRequestProxyAuthentication { BasicScheme authscheme = new BasicScheme(); Credentials creds = new UsernamePasswordCredentials("user", "secret"); - AuthScope authscope = new AuthScope("localhost", 8080, "auth-realm", "http"); BasicHeader challenge = new BasicHeader(AUTH.PROXY_AUTH, "BASIC realm=auth-realm"); authscheme.processChallenge(challenge); AuthState authstate = new AuthState(); authstate.setAuthScheme(authscheme); - authstate.setAuthScope(authscope); authstate.setCredentials(creds); context.setAttribute(ExecutionContext.HTTP_CONNECTION, conn); @@ -277,8 +271,7 @@ public class TestRequestProxyAuthentication { authstate.setAuthScheme(authscheme); authstate.setCredentials(creds); - // No challenge - authstate.setAuthScope(null); + authstate.setChallengeState(AuthChallengeState.UNCHALLENGED); context.setAttribute(ExecutionContext.HTTP_CONNECTION, conn); context.setAttribute(ClientContext.PROXY_AUTH_STATE, authstate); diff --git a/httpclient/src/test/java/org/apache/http/client/protocol/TestRequestTargetAuthentication.java b/httpclient/src/test/java/org/apache/http/client/protocol/TestRequestTargetAuthentication.java index 7c4d55ab0..2070464ea 100644 --- a/httpclient/src/test/java/org/apache/http/client/protocol/TestRequestTargetAuthentication.java +++ b/httpclient/src/test/java/org/apache/http/client/protocol/TestRequestTargetAuthentication.java @@ -32,7 +32,7 @@ import org.apache.http.Header; import org.apache.http.HttpRequest; import org.apache.http.HttpRequestInterceptor; import org.apache.http.auth.AUTH; -import org.apache.http.auth.AuthScope; +import org.apache.http.auth.AuthChallengeState; import org.apache.http.auth.AuthState; import org.apache.http.auth.Credentials; import org.apache.http.auth.UsernamePasswordCredentials; @@ -66,13 +66,11 @@ public class TestRequestTargetAuthentication { BasicScheme authscheme = new BasicScheme(); Credentials creds = new UsernamePasswordCredentials("user", "secret"); - AuthScope authscope = new AuthScope("localhost", 8080, "auth-realm", "http"); BasicHeader challenge = new BasicHeader(AUTH.WWW_AUTH, "BASIC realm=auth-realm"); authscheme.processChallenge(challenge); AuthState authstate = new AuthState(); authstate.setAuthScheme(authscheme); - authstate.setAuthScope(authscope); authstate.setCredentials(creds); context.setAttribute(ClientContext.TARGET_AUTH_STATE, authstate); @@ -91,13 +89,11 @@ public class TestRequestTargetAuthentication { BasicScheme authscheme = new BasicScheme(); Credentials creds = new UsernamePasswordCredentials("user", "secret"); - AuthScope authscope = new AuthScope("localhost", 8080, "auth-realm", "http"); BasicHeader challenge = new BasicHeader(AUTH.WWW_AUTH, "BASIC realm=auth-realm"); authscheme.processChallenge(challenge); AuthState authstate = new AuthState(); authstate.setAuthScheme(authscheme); - authstate.setAuthScope(authscope); authstate.setCredentials(creds); context.setAttribute(ClientContext.TARGET_AUTH_STATE, authstate); @@ -116,14 +112,12 @@ public class TestRequestTargetAuthentication { BasicScheme authscheme = new BasicScheme(); Credentials creds = new UsernamePasswordCredentials("user", "secret"); - AuthScope authscope = new AuthScope("localhost", 8080, "auth-realm", "http"); BasicHeader challenge = new BasicHeader(AUTH.WWW_AUTH, "BASIC realm=auth-realm"); authscheme.processChallenge(challenge); AuthState authstate = new AuthState(); authstate.setAuthScheme(authscheme); - authstate.setAuthScope(authscope); authstate.setCredentials(creds); context.setAttribute(ClientContext.TARGET_AUTH_STATE, authstate); @@ -207,8 +201,7 @@ public class TestRequestTargetAuthentication { authstate.setAuthScheme(authscheme); authstate.setCredentials(creds); - // No challenge - authstate.setAuthScope(null); + authstate.setChallengeState(AuthChallengeState.UNCHALLENGED); context.setAttribute(ClientContext.TARGET_AUTH_STATE, authstate); diff --git a/httpclient/src/test/java/org/apache/http/client/protocol/TestResponseAuthCache.java b/httpclient/src/test/java/org/apache/http/client/protocol/TestResponseAuthCache.java index 6ed4e301e..d8ff87ea5 100644 --- a/httpclient/src/test/java/org/apache/http/client/protocol/TestResponseAuthCache.java +++ b/httpclient/src/test/java/org/apache/http/client/protocol/TestResponseAuthCache.java @@ -33,10 +33,8 @@ import org.apache.http.HttpResponse; import org.apache.http.HttpResponseInterceptor; import org.apache.http.HttpVersion; import org.apache.http.auth.AUTH; -import org.apache.http.auth.AuthScope; +import org.apache.http.auth.AuthChallengeState; import org.apache.http.auth.AuthState; -import org.apache.http.auth.Credentials; -import org.apache.http.auth.UsernamePasswordCredentials; import org.apache.http.client.AuthCache; import org.apache.http.impl.auth.BasicScheme; import org.apache.http.impl.client.BasicAuthCache; @@ -52,10 +50,6 @@ public class TestResponseAuthCache { private HttpHost target; private HttpHost proxy; - private Credentials creds1; - private Credentials creds2; - private AuthScope authscope1; - private AuthScope authscope2; private BasicScheme authscheme1; private BasicScheme authscheme2; private AuthState targetState; @@ -66,10 +60,6 @@ public class TestResponseAuthCache { this.target = new HttpHost("localhost", 80); this.proxy = new HttpHost("localhost", 8080); - this.creds1 = new UsernamePasswordCredentials("user1", "secret1"); - this.creds2 = new UsernamePasswordCredentials("user2", "secret2"); - this.authscope1 = new AuthScope(this.target); - this.authscope2 = new AuthScope(this.proxy); this.authscheme1 = new BasicScheme(); this.authscheme2 = new BasicScheme(); @@ -100,13 +90,11 @@ public class TestResponseAuthCache { this.authscheme2.processChallenge( new BasicHeader(AUTH.PROXY_AUTH, "BASIC realm=auth-realm")); + this.targetState.setChallengeState(AuthChallengeState.CHALLENGED); this.targetState.setAuthScheme(this.authscheme1); - this.targetState.setCredentials(this.creds1); - this.targetState.setAuthScope(this.authscope1); + this.proxyState.setChallengeState(AuthChallengeState.CHALLENGED); this.proxyState.setAuthScheme(this.authscheme2); - this.proxyState.setCredentials(this.creds2); - this.proxyState.setAuthScope(this.authscope2); HttpContext context = new BasicHttpContext(); context.setAttribute(ExecutionContext.HTTP_TARGET_HOST, this.target); @@ -159,13 +147,11 @@ public class TestResponseAuthCache { public void testAuthSchemeNotCompleted() throws Exception { HttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1, 200, "OK"); + this.targetState.setChallengeState(AuthChallengeState.CHALLENGED); this.targetState.setAuthScheme(this.authscheme1); - this.targetState.setCredentials(this.creds1); - this.targetState.setAuthScope(this.authscope1); + this.proxyState.setChallengeState(AuthChallengeState.CHALLENGED); this.proxyState.setAuthScheme(this.authscheme2); - this.proxyState.setCredentials(this.creds2); - this.proxyState.setAuthScope(this.authscope2); HttpContext context = new BasicHttpContext(); context.setAttribute(ExecutionContext.HTTP_TARGET_HOST, this.target); @@ -189,13 +175,11 @@ public class TestResponseAuthCache { this.authscheme2.processChallenge( new BasicHeader(AUTH.PROXY_AUTH, "BASIC realm=auth-realm")); + this.targetState.setChallengeState(AuthChallengeState.UNCHALLENGED); this.targetState.setAuthScheme(this.authscheme1); - this.targetState.setCredentials(this.creds1); - this.targetState.setAuthScope(null); + this.proxyState.setChallengeState(AuthChallengeState.UNCHALLENGED); this.proxyState.setAuthScheme(this.authscheme2); - this.proxyState.setCredentials(this.creds2); - this.proxyState.setAuthScope(null); HttpContext context = new BasicHttpContext(); context.setAttribute(ExecutionContext.HTTP_TARGET_HOST, this.target); @@ -221,13 +205,11 @@ public class TestResponseAuthCache { this.authscheme2.processChallenge( new BasicHeader(AUTH.PROXY_AUTH, "BASIC realm=auth-realm")); + this.targetState.setChallengeState(AuthChallengeState.FAILURE); this.targetState.setAuthScheme(this.authscheme1); - this.targetState.setCredentials(null); - this.targetState.setAuthScope(this.authscope1); + this.proxyState.setChallengeState(AuthChallengeState.FAILURE); this.proxyState.setAuthScheme(this.authscheme2); - this.proxyState.setCredentials(null); - this.proxyState.setAuthScope(this.authscope2); HttpContext context = new BasicHttpContext(); context.setAttribute(ExecutionContext.HTTP_TARGET_HOST, this.target);