11.10. Basic Authentication

Problem

You need to access information protected by HTTP Basic Authentication.

Solution

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>

Discussion

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 );

Warning

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.

See Also

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.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
13.58.51.228