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.