Create a UsernamePasswordCredentials object with a username and password. Add this Credentials object to the instance of HttpState associated with an HttpClient object. HttpClient will attempt to execute a message,
and the server will respond with 401
response code; HttpClient will then
retry the request with the appropriate Authorization header. The following example
uses a UsernamePasswordCredentials
object to access a protected resource:
import org.apache.commons.httpclient.Credentials;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpException;
import org.apache.commons.httpclient.HttpMethod;
import org.apache.commons.httpclient.UsernamePasswordCredentials;
import org.apache.commons.httpclient.methods.GetMethod;
HttpClient client = new HttpClient( );
HttpState state = client.getState( );
// Set credentials on the client
Credentials credentials =
new UsernamePasswordCredentials( "testuser", "crazypass" );
state.setCredentials( null, null, credentials );
String url = "http://www.discursive.com/jccook/auth/";
HttpMethod method = new GetMethod( url );
client.executeMethod( method );
String response = method.getResponseBodyAsString( );
System.out.println( response );
method.releaseConnection( );This example executes a GetMethod, the server requests credentials, and the credentials are sent to the server.
The final response is:
<html> <head> <title>Secure JCCook Example</title> </head> <body> <h1>Hello Secure World!</h1> </body> </html>
The previous example added a UsernamePasswordCredentials object to the
HttpState with a null authentication realm and a null host; this makes the supplied UsernamePasswordCredentials object the default
instance to use for all authentication realms and hosts. The requests
and responses created by this example demonstrate the inner-workings of
HttpClient, which sent the following
request when the GetMethod was
executed:
GET /jccook/auth/ HTTP/1.1 User-Agent: Jakarta Commons-HttpClient/3.0final Host: www.discursive.com
The server then responds with a 401 response code, telling the client that
authorization is required. The WWW-Authenticate header specifies that the server is expecting Basic
authentication, and the authentication realm is jccook realm:
HTTP/1.1 401 Authorization Required Date: Fri, 14 May 2004 20:40:59 GMT Server: Apache/2.0.48 (Fedora) WWW-Authenticate: Basic realm="jccook realm" Content-Length: 487 Content-Type: text/html; charset=iso-8859-1 DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN"> <html><head> title>401 Authorization Required</title> </head><body> .... error message ....
The server did not return the information needed, and another
request needs to be made, sending the credentials in an Authorization request header. Since the
initial request was made with HTTP/1.1, the connection is not closed after
the response, and a second request will be sent over the same
connection. This second request is the same as the first request except
for an Authorization header.
HttpClient looked at the associated
HttpState object and located the
appropriate Credentials object to use
to create the Authorization
header:
GET /jccook/auth/ HTTP/1.1 User-Agent: Jakarta Commons-HttpClient/3.0final Host: www.discursive.com Authorization: Basic dGVzdHVzZXI6Y3JhenlwYXNz
Finally, the server replies with a 200 response code and the content of the
requested resource:
HTTP/1.1 200 OK Date: Fri, 14 May 2004 20:40:59 GMT Server: Apache/2.0.48 (Fedora) Last-Modified: Wed, 05 May 2004 02:51:59 GMT ETag: "a06d2-76-829811c0" Accept-Ranges: bytes Content-Length: 118 Content-Type: text/html; charset=UTF-8 <html> <head> <title>Secure JCCook Example</title> </head> <body> <h1>Hello Secure World!</h1> </body> </html>
HttpClient waits for the server
to send back a 401 response code
before sending the appropriate credentials. If you are accessing a
resource, which is known to be protected by authentication, you can
configure the HttpState object to
send credentials preemptively, obviating the need for the client to
react to a 401 response code. In
other words, the Authorization
header is supplied in the initial request. To configure HttpClient to send credentials preemptively,
retrieve an HttpClientParams object
from HttpClient via the getParams( ) method, and call setAuthenticationPreemptive(true) as
follows:
HttpClientParams params = client.getParams( ); params.setAuthenticationPreemptive( true );
Basic authentication involves sending an unencrypted password in
the request. The value of the Authorization header in the request is
simply testuser:crazypass sent
through a Base64 encoding utility.
If you are working on a system that uses Basic authentication, make
sure that any system that performs authentication does so over
SSL; otherwise, your password
will fall into the wrong hands.
If you want to convince someone that using Basic authentication
without encryption is a bad idea, download the network protocol analyzer
Ethereal (http://www.ethereal.com/), and
capture some network traffic. Identify an Authorize header and run the value through a
Base64 decoder (http://www.securitystats.com/tools/base64.php).
Create a custom T-shirt or coffee mug with your friend's username and
password, and present it to him as a gift.
