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.
13.58.51.228