Welcome!

Welcome to the official BlackBerry Support Community Forums.

This is your resource to discuss support topics with your peers, and learn from each other.

inside custom component

Java Development

How to enable HTTP Authentication in your BrowserField2 application

by Retired on ‎11-01-2010 10:47 AM (7,264 Views)

 

Have you have wondered why pages requiring HTTP authentication cannot be properly loaded in your BrowserField2 application?

 

In fact, HTTP Authentication (http://en.wikipedia.org/wiki/Basic_access_authentication) does not come standard in the BrowserField2 API. This means that pages requiring HTTP authentication cannot be properly viewed in your BrowserField2 application since user credentials cannot be typed in and sent to the HTTP server for validation.

 

This article explains in detail how the BrowserField2 API can be extended in order to enable support for HTTP authentication. In the attachments you will find the source code of a complete BrowserField2 application for the screenshot shown in Figure 1 below.

 

 

bb_http_authentication.PNG

 

Figure 1. A BrowserField2 application supporting HTTP Authentication
(source code attached to this article)

 

 

 

1. Background

  

HTTP Authentication: HTTP authentication is a feature of the HTTP protocol that allows Web servers to require HTTP clients to authenticate in order to have access to protected resources. HTTP authentication is currently supported by most of modern desktop and mobile browsers including the BlackBerry® Webkit Browser. The two most common HTTP authentication mechanisms supported are basic and digest. In a typical HTTP authentication session, the Web server challenges the HTTP client by asking for proper credentials (user and password) to access a resource. The Web server signals the need to authenticate by means of specific HTTP response codes, i.e., 401 (Unauthorized) and 407 (Proxy authentication required). The HTTP client (a.k.a. user agent) usually pops up a dialog to ask users for proper credentials before it send the credentials back to the Web server as part of the next HTTP request header. If the credentials are accepted by the server access to the resource is granted, otherwise another challenge is sent back to the client. Discussing the intricacies of HTTP Authentication is out of the scope of this article. For more information we would like to refer the readers to the following resources: RFC 2617 (http://tools.ietf.org/html/rfc2617), the W3C HTTP protocol code definitions (http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html), or Wikipedia articles on HTTP authentication (http://en.wikipedia.org/wiki/Basic_access_authentication).

 

BrowserField2's Protocol Controller: The BrowserField2 API offers several extensions points that allow developers to add new features or replace standard functionality. Among those extension points is the ProtocolController component that handles navigation (e.g., a click was linked on your page) and resource (e.g., an image or a CSS file needs to be loaded in your page) requests through a variety of protocols (e.g., http, https, local, file). The ProtocolController uses Handlers to address specific protocols. For instance, the API currently uses a Handler to deal with "http://" and "https://" requests (e.g., http://www.rim.com), another Handler for the "local:///" protocol (e.g., local:///index.html), and yet another Handler for the "file:///" protocol (e.g., file:///image.png"). Thankfully, ProtocolController's Handlers can be overridden offering developers an opportunity to replace standard functionality with their own implementation.

 

In this article, we replace the standard Handler that deals with "http" requests with our own Handler since we want to enable support for HTTP authentication. The next session shows how a new Handler can be created for HTTP requests.

 

  

2. Creating a ProtocolController Handler

  

As mentioned, ProtocolController Handlers have to deal with navigation and resource requests. A navigation request is triggered either programmatically (e.g., via BrowserField.requestContent() for instance) or by a user (e.g., by clicking on a link) that is interpreted as an intent to navigate to a new page or resource. A Handler might take whatever action is wanted upon catching the navigation request event (e.g., load a new page on the BrowserField based on the link that was clicked). 

 

A resource request is typically triggered by the HTML rendering engine when a new resource such as an image, video, CSS or Javascript® file needs to be loaded as part of a Web page's resource. In this context, it is expected that the Handler returns a valid InputConnection that can be used by the rendering engine to read the resource's data.

 

The source code below shows how to create a new ProtocolController Handler by extending two public BrowserField2 interfaces: BrowserFieldNavigationRequestHandler and BrowserFieldResourceRequestHandler. These interfaces provide method signatures handleNavigation() and handleResource() that should be implemented by Handlers. Note that handleResource() signature requires an InputConnection to be returned as previously mentioned. Both signatures take a BrowserFieldRequest as argument that contains detailed information about the request being made.

 

 

public class MyNewProtocolControllerHandler 
implements BrowserFieldNavigationRequestHandler,
BrowserFieldResourceRequestHandler {

public void handleNavigation(BrowserFieldRequest request) {
// your code here
}

public InputConnection handleResource(BrowserFieldRequest request) {
// your code here
}

}

 

3. Creating the HTTP Authentication Handler

 

The snipped code below shows a new ProtocolController Handler named HttpAuthenticationTransportResourceHandle that will handle HTTP authentication requests and replace the standard BrowserField2 "http" Handler.

 

We start by implementing public interfaces  BrowserFieldNavigationRequestHandler and BrowserFieldResourceRequestHandler and defining a constructor that receives and stores a reference a BrowserField object. Note the use of helper class AuthScheme that deals with HTTP authentication functionality and a Hashtable that stores accepted credentials to prevent the same credential to be requested twice for the same authenticated page/resource. It is out of the scope of this article to discuss the implementation of helper classes that deal with HTTP Authentication such as AuthScheme and others classes found in the source code attached to this article.

 

 

public class HttpAuthenticationTransportResourceHandler 
implements BrowserFieldNavigationRequestHandler,
BrowserFieldResourceRequestHandler {

protected BrowserField _browserField;
 
   // Max number of attempts to enter valid credentials
   final private static int MAX_ATTEMPTS = 3;
   
   private AuthScheme _authScheme;
   private Hashtable _credentials;
   
public HttpAuthenticationTransportResourceHandler(BrowserField browserField) {
        _browserField = browserField;
        _credentials = new Hashtable();
  }

 

Next, methods handleNavigation() and handleResource() are implemented. Note that method handleNavigation() relies on method handleResource() to grab a valid connection and to perform HTTP authentication, if necessary, to load the resource being requested. Once the connection is retrieved a call to BrowserField's displayContent() is made to display the page's content to the user. In fact, this mirrors the behavior of the standard "http" Handler.

 

Method handleResource() below uses the BrowserField ConnectionManager's component to retrieve an input connection for the resource being requested and passes the connection along to method httpAuthenticate() that will take care of authenticating the user, if necessary.

 

/**
* Simply grabs the resource and displays the content.
*/
 public void handleNavigation(BrowserFieldRequest request) throws Exception {
  InputConnection connection = handleResource(request);
    _browserField.displayContent(connection, request.getURL());
}
   
/**
* Returns an input connection where the resource can be read from
*/
public InputConnection handleResource(BrowserFieldRequest request)
throws Exception {
InputConnection inputConnection =
_browserField.getConnectionManager().makeRequest(request);
    if ( inputConnection instanceof HttpConnection ) {
    inputConnection=httpAuthenticate((HttpConnection)inputConnection, request);
    }
    return inputConnection;
 }  

 

Private helper method httpAuthenticate() receives the inputConnection and the BrowserFieldRequest an checks whether the HTTP authentication scheme is supported. In our attached sample code, schemes basic and digest are supported. This method also returns true if the resource being requested does not require HTTP authentication.

 

A while loop is used to continuously ask for user credentials until one of the following options is true: i) the credentials provided by the user are accepted, ii) the user has cancelled the request, or iii) the number of attempts has reached the maximum allowed. Within the loop, setUserCredentials() is called to either pop up a dialog to capture user's credentials or to reuse credentials saved on local Hashtable for a given HTTP domain or realm (realm refers to a specific HTTP authentication domain: http://tools.ietf.org/html/rfc2617). Once the credentials are validated, an HTTP connection is returned and the page's content is finally revealed and displayed to the user. If the credentials are incorrect or the user has cancelled or the maximum number of attempts has been reached, the user will see contents sent from the Web server informing that access to the page has not been granted.

 

private InputConnection httpAuthenticate(
HttpConnection httpConnection, BrowserFieldRequest request ) {
   try {
      // True if/when the user has given up (canceled) authentication
      boolean userCanceledAuthentication = false;
                   
      // Keep track of how many attempts we make.
      int attemptNumber = 1;
                   
      // Check if the HTTP authentication scheme is supported
      if ( authSchemeSupported(httpConnection) ) {
         // Loop while user is not authenticated and has not canceled the
         // authentication process, and we haven't made too many requests    
         while ( requiresAuthentication(httpConnection) &&
!userCanceledAuthentication &&
(attemptNumber <= MAX_ATTEMPTS)) {
                          
                           
            // User has provided a username and password for validation
            if ( setUserCredentials((attemptNumber > 1) ? true : false) ) {
               httpConnection =
requestContentWithCredentials(request, httpConnection);
            }
            // User has decided to cancel authentication
               else {
                  userCanceledAuthentication = true;
               }                        
            // Starting new attempt (possibly), so increment the counter.
            attemptNumber++;
         }
      }              
   } catch( Throwable e ) {
        // If it breaks somewhere, just let the page load unauthenticated.
     }
     // Return the httpConnection, whether it is authenticated or not.
     return httpConnection;
}  

 

 

4. Using the New HTTP Authentication Handler in your application

  

Now that the new ProtocolController Handler HttpAuthenticationTransportResourceHandler has been created we need to attach it to the BrowserField in order to use it from our application.

 

In the appropriate location in your application you need to create the BrowserField object . . .

 

BrowserField browserField = new BrowserField();

 

. . .  then, you create an instance of you new HttpAutheticationTransportResourceHandler . . .

 

HttpAuthenticationTransportResourceHandler 
handler = new HttpAuthenticationTransportResourceHandler(browserField);

 

. . .  and you finally attach the new Handler to the BrowserField's standard ProtocolController.

 


ProtocolController controller = (ProtocolController)browserField.getController();

 

Once the new Handler is attached, HTTP Authentication support is enabled.

 

 

Hey, now your BrowserField2 application is ready for HTTP authentication challenges! 

  

Have fun!

Users Online
Currently online: 20 members 1,249 guests
Please welcome our newest community members: