Using Selenium to test JSF (myFaces impl) application

I have been looking for a good way to do integration testing of webapplications done in JSF, and decided to give Selenium a try.
First I had a look at the Selenium IDE, it is basically a Firefox “record” tool that remembers the actions you do in the webapp, and then saves these actions as a test-template for you to use later on. But I didn’t want to limit myself to any browser, and I would also like to keep an opening for some continous build processes and frameworks. I therefore decided to go for Selenium Remote Control (Selenium RC), which also allows me to write the tests in java.

I know that Selenium recommends using TestNG instead of JUnit (JUnit should be considered a unit testing tool, not for integration testing) , but since I had some (moderate) experience with JUnit from before I decided to go for this. So I downloaded Selenium RC, and created a new java-project in Eclipse with selenium-java-client-driver.jar, selenium-server.jar and junit.jar in my lib-folder. Both selenium-java-client-driver.jar and junit.jar should be added to the build path, but there’s no need to add selenium-server.jar.

Before you run your tests the selenium server needs to be running, and you can manually start this from command-line by running the command “java -jar selenium-server.jar”. But then, you might want to add some options or specify some properties, and perhaps you don’t want to start messing around with the cmd-window at all. So I created an ant-task for starting and stopping the server. This task I can then set as dependency in another task that runs my tests, but this is of course up to you.

The start task:

	<target name="selenium-start">
		<java jar="${lib.test.dir}/${selenium-jar}" fork="true" spawn="true">
			<arg  line="-port ${selenium.port}" />
			<arg  line="-debug" />
			<arg  line="-log ${build.dir}/selenium.log" /> 		
		</java>
	</target>

The stop task:

	<target name="selenium-stop" description="Stop the Selenium RC server on port ${selenium.port}">
		<get taskname="selenium-shutdown" dest="${build.dir}/selenium.log" src="http://localhost:${selenium.port}/selenium-server/driver/?cmd=shutDown" ignoreerrors="true" />
	</target>

So, what about the testing?

If you’re familiar with JUnit, you know that you need to define the setUp() and tearDown() method. Selenium have created a class SeleneseTestCase that extends TestCase of JUnit, and this class is giving you some selenium-utilities which can be nice to have. I decided to create my tests extending the SeleneseTestCase, but you don’t have to – you can extend TestCase directly. Also, to avoid having to specify the setup() and tearDown() method in all my test-cases I created an abstract class called DefaultTest which I would extend for my test-cases. The DefaultTest has this definition:

public abstract class DefaultTest extends SeleneseTestCase
{
	protected Selenium browser;
	public static final String DEFAULT_TIMEOUT = "20000";
	public static final String BROWSER_FIREFOX = "*firefox";
	public static final String BROWSER_CHROME = "*chrome";
	public static final String BROWSER_IE = "*iexplore";
	
	public void setUp() throws Exception
	{
		browser = new DefaultSelenium("localhost", 6666, BROWSER_CHROME, "http://localhost/Test/");
		browser.start();
	}

	public void tearDown() throws Exception
	{
		browser.stop();
	}
}

To create the “virtual” browser object in Selenium you need to specify the server-host, which port to use, which browser to simulate and so on. I’m doing my tests against a local jboss-server running on port 8080. Note that jboss uses the default port of Selenium (4444), so I specified 6666 for my selenium server to run.

To be able to simulate a user typing something or pressing links, it’s obvious that we in the java-code need some way of locating the different web-elements. In Selenium this is referred to as “locators,” in java you specify them as String objects. You can locate an element in different ways, I mention some of them here:

  • By id: String locator = “id=theIdOfMyComponent”;
  • By name: String locator = “name=theNameOfMyComponent”;
  • By xpath: String locator = “xpath=//table[@id=’myTable’]/tbody/tr/td[2]/span/a”;
  • By link content: String locator = “link=ClickMe”;
  • By table-cell-refernce (TableId.Row.Cell): String locator = “myTable.1.0”;
  • By DOM: String locator = “dom=document.forms[‘myForm’].myElement”;

To start with something simple, we can try a TestCase for logging on to an application. As a convention to follow all the methods in your test-cases should start with “test”, like testLogin():

public class LoginTestCase extends DefaultTest
{
	public final void testLogin()
	{
		String userNameLocator = "name=username";
		String passwordLocator = "name=password";
		String componentLocator = "id=idOfTheComponentIExpectToBeThereAfterSuccessfullyLoggingIn";
		
		browser.open("http://localhost:8080/MyWebbAppContextRoot/");
		browser.type(userNameLocator, "myUsername");
		browser.type(passwordLocator, "myPassword");
		browser.click("id=submitButton");
		browser.waitForPageToLoad(DEFAULT_TIMEOUT);
		assertEquals("The title I expect", browser.getTitle());
		assertTrue(browser.isElementPresent(componentLocator));
		
	}
	
}

You run the test by right-clicking the class (run all tests in the class) or individually on each method -> select Run As -> select JUnitTest. Of course this can also be done from an ant task.

The browser.open() specifies the initial page that should be loaded in the browser. Then you can see that we fill in a value for the username and password, and click a button. Whenever there is a click that requires a page reload, you have to follow that command by a “browser.waitForPageToLoad()”. I set my standard timeout to 20 sec (20000ms), but if the response is sent earlier the browser acts upon it immediately. Then we do an assertion on the title of the page we were sent to, as well as an assertion to check that an expected component on this page actually exist. So, this is a testCase that tests for a successful logon. Another test that could be done is for example to pass invalid username/password, to see that unsuccessful logons are handled correctly.

Testing your webapp like this is integration testing, not unit testing. It is therefore likely that to be able to do your test you need to other actions first, like you follow a chain of commands; you might have to log on, maybe click a link to go on the proper page, or you need to do some other actions before you can do your assertions. Thus, I created some static methods in a utility-class that handles the most common operations, so that I can reuse those from my TestCases. Consider a class like this:

public class InteractionUtil extends DefaultTest
{
	public static void login(Selenium browser)
	{
		String userNameLocator = "name=username";
		String passwordLocator = "name=password";
		
		browser.open("http://localhost:8080/MyWebbAppContextRoot/");
		browser.type(userNameLocator, "myUsername");
		browser.type(passwordLocator, "myPassword");
		browser.click("id=submitButton");
		browser.waitForPageToLoad(DEFAULT_TIMEOUT);
	}
}

Then, my testLogin() method would simply be like this:


	public final void testLogin()
	{
		String componentLocator = "id=idOfTheComponentIExpectToBeThereAfterSuccessfullyLoggingIn";
		InteractionUtil.login(browser);
		assertEquals("The title I expect", browser.getTitle());
		assertTrue(browser.isElementPresent(componentLocator));
	}

And it is very easy to also include this logon-action in other testCases where it is needed. All actions you need to do often can go into such a utility-class.

As a final example I will show how to use the JsCookMenu of tomahawk library from Selenium. I struggled quite a bit with this one before I was able to make the action trigger. Since triggering an element in a dropdown-menu like this can be considered a “generic” action I include it in my utility-class:


	public static void clickJsCookMenu(Selenium browser, String theme, String jsCookId, String itemValue)
	{
		String fieldRowLocator = "xpath=//div[@id='"+jsCookId+"']/div/table/tbody/tr[@class='"+theme+"MenuItem' and td = '"+itemValue+"']";
		String jsCookMenuTdLocator = "xpath=//div[@id='"+jsCookId+"']/table/tbody/tr/td[@class='"+theme+"MainItem']";
		String fieldRowHoverLocator = "xpath=//div[@id='"+jsCookId+"']/div/table/tbody/tr[@class='"+theme+"MenuItemHover']";
		String fieldRowActiveLocator = "xpath=//div[@id='"+jsCookId+"']/div/table/tbody/tr[@class='"+theme+"MenuItemActive']";
		
		browser.mouseOver(jsCookMenuTdLocator);
		browser.waitForCondition("selenium.isVisible(\""+ fieldRowLocator+"\");", DEFAULT_TIMEOUT);
		browser.mouseOver(fieldRowLocator);
		browser.mouseDown(fieldRowHoverLocator);
		browser.mouseUp(fieldRowActiveLocator);
	
		browser.waitForPageToLoad(DEFAULT_TIMEOUT);
	}

To explain a bit, I pass as parameters the browser object, the jsCook theme being used (office, ie and so on), the id I’ve given the jscookMenu component in my jsp and the value/text of the item I want to click. I first do a mouseOver to display the menu, and notice the “waitForCondition” command that follows. This means that the browser should wait for the menu to be visible. Then i figured out I needed to do a mouse-over on the row holding the item. This makes the css class change, so I do mouseDown on the “hovered” row. But the mouseDown-event in the jsCook javascript doesn’t trigger the link, actually a mouseUp does, so finally I do a mouseUp-event on the active row. And of course I then wait for the page to reload.

Then from my test-method I can simply do:


	public void testJsCookMenu()
	{
		InteractionUtil.login(browser);
		UserInteractionUtil.clickJsCookMenu(browser, "ThemeIE", "myJsCookId", "theElementIWantToClick");
		//--- assertions ---
	}

I hope this post will give you a brief understanding on how to use Selenium for testing your webapps!

Mod_gzip – how to make configuration work for Apache 1.3, mod_jk and JBOSS/JSF

I’ve been working a couple of days trying to get mod_gzip to work with apache 1.3, enabling compression for JSF application (.faces). Everything seemed so easy in the configuration described here, but I actually troubled quite a lot with it, and wanted to share what I’ve learned.πŸ™‚ I used this page as a starting point for my digging into mod_gzip. I use mod__jk to forward the request to jboss’ tomcat server.

Firs and most important of all, the configuration I use that make things work with JSF:

LoadModule gzip_module     libexec/mod_gzip.so

<IfModule mod_gzip.c>
mod_gzip_on                   Yes
mod_gzip_can_negotiate        Yes
mod_gzip_static_suffix        .gz
AddEncoding              gzip .gz
mod_gzip_update_static        No
mod_gzip_command_version      '/mod_gzip_status'
mod_gzip_temp_dir             /tmp
mod_gzip_keep_workfiles       No
mod_gzip_minimum_file_size    300
mod_gzip_maximum_file_size    500000
mod_gzip_maximum_inmem_size   60000
mod_gzip_min_http             1000
mod_gzip_handle_methods        GET POST
mod_gzip_dechunk              Yes
mod_gzip_send_vary            On

#Files and items to compress
mod_gzip_item_include         file       \.html$
mod_gzip_item_include         file       \.htm$
mod_gzip_item_include         file       \.js$
mod_gzip_item_include         file       \.js
mod_gzip_item_include         file       \.faces
mod_gzip_item_include         file       \.css$
mod_gzip_item_include         file       \.jsp$
mod_gzip_item_include         file       \.jsp

mod_gzip_item_include         uri        \.jsp$
mod_gzip_item_include         uri        \.jsp

mod_gzip_item_include         handler    \.*
mod_gzip_item_include         handler    \.*$

mod_gzip_item_include         mime       ^text/html$
mod_gzip_item_include         mime       ^text/html
mod_gzip_item_include         mime      ^text/plain
mod_gzip_item_include         mime      ^text/plain$
mod_gzip_item_include         mime       ^text/xml$
mod_gzip_item_include         mime       ^text/css$
mod_gzip_item_include         mime       ^text/javascript$
mod_gzip_item_include         mime       ^text/javascript
mod_gzip_item_include         mime       ^application/x-javascript$
mod_gzip_item_include         mime       ^application/javascript$

CustomLog                     logs/mod_gzip.log common_with_mod_gzip_info2
LogFormat                     "%h %l %u %t \"%V %r\" %<s %{Content-type}o  %b mo
d_gzip: %{mod_gzip_result}n In:%{mod_gzip_input_size}n -< Out:%{mod_gzip_output_
size}n = %{mod_gzip_compression_ratio}n pct." common_with_mod_gzip_info2
</IfModule>

I will just say (cause it is important) that without the two lines including the “handler” patterns, I couldn’t get any compression to work when I was playing with JSF applications. All the logging lines had status “DECLINED:EXCLUDED”.

The first thing to do when you’re supposed to do this would be to enable logging of gzip to understand what is going on. Then based on status-codes you can get a clue to why a file is compressed or not.

Add the following line in your conf:
LogFormat “%h %l %u %t \”%V %r\” %<s %b mod_gzip: %{mod_gzip_result}n In:%{mod_gzip_input_size}n -< Out:%{mod_gzip_output_size}n = %{mod_gzip_compression_ratio}n pct.” common_with_mod_gzip_info2

A problem that troubled me were when I got prints like this:
213.162.235.138 – – [21/Aug/2008:15:13:44 +0200] “localhost.localdomain GET /Url/css/styles.css HTTP/1.1” 200 text/plain 0 mod_gzip: SEND_AS_IS:NO_200 In:0 -< Out:0 = 0 pct.

Apache reports the file as 200, but gzip ends up with status code “SEND_AS_IS:NO_200”. Ok, so we go to check the meaning of the status codes, but that didn’t tell us much. Confusing? It really means that this file is cached in the browser, and will not be compressed because of this. Try ctrl+F5 to clear the cache, then it should compress that file as well.

Also, even if I included the line “mod_gzip_item_include file \.js$” to compress javascript, for all the javascripts it reported “SEND_AS_IS:RESPONSE_CONTENT_TYPE_EXCLUDED”
I troubled with this one, but then I remembered something I read on the internet: “The order of processing during each of both phases is not important, but to trigger the compression of a request’s content this request a) must match at least one include rule in each of both phases and # b) must not match an exclude rule in any of both phases.”

In other words, for some reason it didn’t find an include rule for javascript in both phases. I had included mime type ^text/javascript, so I couldn’t understand this. But I felt like navigating blindly, cause I never saw what mime-type the request was. So I added the following to my log statement: “%{Content-type}o” – which would print out the mime-type as well. Then I saw that for some javascripts the mime-type were application/x-javascript. I included this in the include-list as well, then case was closedπŸ™‚

Hope this post will help others in the same situation, or at least it might give you a clue to what is going onπŸ™‚

Ajax ReRendering – How to reRender part of your page in Myfaces using Richfaces

If you read this post I assume you have a general knowledge about what Ajax is, and what capabilities lies within. As a web-developer, there might be times where you would like to not do a full submit of your page, but you would actually like to just update a small part of the page. An application that achieves this gives the user a more “desktop-application”-like experience, and it will mostly also be a saver when it comes to performance, as you only load a part of the page – as well as the data going to be displayed in it.

For Myfaces, both 1.1 and 1.2 specification, there is a component library named RichFaces. The components there are nice to use for adding ajax-features to your application, and there are also possibilities of adding those capabilities to non-ajax components in myFaces or Tomahawk libraries.

You can download the libraries from here: RichFaces. Depending on the version of Myfaces you use, you need to get different RichFaces version. For MyFaces 1.1 core you need the RichFaces 3.1.X libraries, for Myfaces 1.2 core you can get the 3.2.X libaries. The 3.2.X libraries does NOT support Myfaces version 1.1

Then, to make use of the new library you need to add the following to your web.xml:

    <filter>
        <display-name>RichFaces Filter</display-name>
        <filter-name>richfaces</filter-name>
        <filter-class>org.ajax4jsf.Filter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>richfaces</filter-name>
        <servlet-name>Faces Servlet</servlet-name>
        <dispatcher>REQUEST</dispatcher>
        <dispatcher>FORWARD</dispatcher>
        <dispatcher>INCLUDE</dispatcher>
    </filter-mapping>

On the top of your jsps you need to include the taglibraries by inserting these lines:
<%@ taglib uri=”http://richfaces.org/rich&#8221; prefix=”rich”%>
<%@ taglib uri=”https://ajax4jsf.dev.java.net/ajax&#8221; prefix=”a4j”%>

So, when it comes to the actual reRendering of components or part of your page, there are several different ways of doing this.

In its simplest form, you can use the a4j:support to add ajax capabilities to ordinary myfaces components. In this example we use it on an inputText. You set the event property (javascript events), give the id of the component(s) you want to reRender, and then you go. Everytime a user releases a key, the reRender will be called, and getting the outText component again:

<h:inputText id="myInput" value="#{myBean.myProperty}">
    <a4j:support event="onkeyup" reRender="outText"></a4j:support>
</h:inputText>

<h:outputText id="outText" value="#{myBean.myProperty}"></h:outputText>

If you use componentBindings, and create those components programmatically, you need to do your custom modification of that component in the setter-method of this component to let the reRendering work. Let’s say you have a panelGrid, and you create it java-side and add two outPutTexts to it. If the value of those outputTexts change, and you want to reRender the panelGrid to display this, then the setter of this component is invoked as long as the getter returns null. So you should do like this:

Jsp:

<h:inputText id="myInput" value="#{myBean.myProperty}">
    <a4j:support event="onkeyup" reRender="outPanel"></a4j:support>
</h:inputText>

<t:panelGrid id="outPanel" binding="#{myBean.htmlPanelGrid}"/>

Java:

public HtmlPanelGrid getHtmlPanelGrid()
{
    return htmlPanelGrid;
}

public void setHtmlPanelGrid(HtmlPanelGrid htmlPanelGrid)
{
    //Clean exisiting children
    htmlPanelGrid.getChildren().clear();

    //Add your modifications
    htmlPanelGrid.getChildren().add(createOutputText("out1","#{myBean.myProperty1}"));
    htmlPanelGrid.getChildren().add(createOutputText("out2","#{myBean.myProperty2}"));

    this.htmlPanelGrid = htmlPanelGrid;
}

private UIComponent createOutputText(String id, String valueBinding)
{
    HtmlOutputText out = new HtmlOutputText();
    out.setId(id);
    ValueBinding vb = FacesContext.getCurrentInstance().getApplication().createValueBinding(
    valueBinding);
    out.setValueBinding("value", vb);

    return out;
}

It is also possible to create the a4j:support programmatically, like this:

HtmlAjaxSupport ajaxSupport = new HtmlAjaxSupport();
ajaxSupport.setEvent("onchange");
ajaxSupport.setId("ajaxSupport");
ajaxSupport.setFocus("myForm:theIdOfComponentIWantToFocusOnAfterAjaxSubmit");
ajaxSupport.setReRender("myForm:idOFComponentIWantToReRender"); 

myUiComponent.getChildren().add(ajaxSupport);

There is also a component that creates a javascript-function for you which you can use to pass properties to your bean, execute actions and finally reRender components. It’s called a4j:jsFunction. Let’s say I have a h:commandButton, and when I click it I want to set a value to a property in my bean, I want to run an action, and then display the results. I could have done this with an t:updateActionListener, but then I would have been forced to do a full submit of the whole page. Instead, I can do it like this:


    //Define javascriptFunction with parameter
    <a4j:form>
        <a4j:jsFunction name="setParameterAndRerender" action="#{myBean.action}" reRender="outPanel" >
             <a4j:actionparam name="param1" assignTo="#{myBean.myProperty1}"  />
         </a4j:jsFunction>
    </a4j:form>

    <t:panelGrid id="outPanel" binding="#{myBean.htmlPanelGrid}"/>

    <h:commandButton value="Click me" onclick="setParameterAndRerender('MyValue');return false;"></h:commandButton>

Notice that I set return false in the onclick of the commandButton to avoid it from submitting. I’ll let ajax handle that.

If you create the a4j:support-object progammatically, I’ve experienced that it doesn’t always find the id of the component you have specified to reRender. To solve this, you can use a combination of this one and the javascript function just described:

HtmlAjaxSupport ajaxSupport = new HtmlAjaxSupport();
ajaxSupport.setEvent("onchange");
ajaxSupport.setId("ajaxSupport");
ajaxSupport.setFocus("myForm:theIdOfComponentIWantToFocusOnAfterAjaxSubmit");

//We don't specify reRender id here, but set a javascript function to run when completed
//ajaxSupport.setReRender("myForm:idOFComponentIWantToReRender");
ajaxSupport.setOncomplete("setParameterAndRerender('MyValue');");

myUiComponent.getChildren().add(ajaxSupport);

So, what about the RichFaces library? In all components the ajax capabilities are included, you don’t have to use a4j:support. When using one of the components the submit will always be an ajax submit, so you can just specify which components to reRender. As a short example, instead of using a h:commandButton you can use a4j:commandButton, like this:

    <a4j:commandButton value="Click me" action="#{myBean.action}"  reRender="outPanel"/>
    <t:panelGrid id="outPanel" binding="#{myBean.htmlPanelGrid}"/>

Also, if you have a part of a page that always should be ajaxRendered, and you are tired of of writing Ids to reRender, simply wrap that part of the page inside an a4j:outputPanel and set the ajaxRendered property to true. In my a4j:commandButton, I don’t have to set the reRender property as this panel is now always reRendered by ajax submits:


    <a4j:commandButton value="Click me" action="#{myBean.action}" />

    <a4j:outputPanel ajaxRendered="true">
        <t:panelGrid id="outPanel" binding="#{myBean.htmlPanelGrid}"/>
    </a4j:outputPanel>

I hope this have given you a brief idea of what is possible to do with ajax/richFaces and also how to do itπŸ™‚

I suggest you to check out the livedemo page to see all the different components that RichFaces give you: Live demo

Migration guide – go from Myfaces 1.1.X to Myfaces 1.2.3

If you are currently using Myfaces 1.1.X and want to start to use Myfaces core 1.2.3, there are certain steps you need to do and to be aware of to be able to make your existing 1.1.X-version application run. JSF 1.2 requires java 1.5 or later, JSP 2.1, JSTL 1.2 and a Java Servlet 2.5 implementation. If you use Jboss, this means that you have to go for jboss version 4.2.2 or higher (supports java5).

  1. First of all you need to download the new Myfaces-1.2 Core libraries, you can do it from here: Myfaces Project
  2. If you have been using Myfaces 1.1.X, you have probably also been using javax.servlet.jar and javax.servlet.jsp.jar. But the 1.2.3 version requires JSP 2.1, JSTL 1.2 and Java Servlet 2.5, so you need to update those libraries. The libraries you want to get are jsp-api-2.1.jar, jstl-1.2.jar and servlet-api-2.5.jar. You can get them from here: Jboss repository.
  3. The libraries are now in place. But you will find out that several classes and methods that existed in Myfaces-1.1.5 are now deprecated. For example, ValueBinding is now ValueExpression, and MethodBinding is MethodExpression. I will give you the different way in creating these programmatically, the way it is with 1.1.5, and the way it should be done in 1.2.3. Note that for ValueExpressions it is necessary to pass the “expected” class as parameter – meaning that if your ValueExpression would be used in the “value” property, the class would probably be java.lang.String. If it was to be used in a “rendered” property, the class should be java.lang.Boolean. If you don’t do this properly you would normally get a class cast exception, or at least some strange results: ValueBinding – 1.1.5
    ValueBinding vb = FacesContext.getCurrentInstance().getApplication().createValueBinding(
                        "#{myBean.myProperty}");
    myComponent.setValueBinding("value", vb);
    

    ValueExpression- 1.2.3

    FacesContext context = FacesContext.getCurrentInstance();
    ValueExpression vex = context.getApplication().getExpressionFactory().createValueExpression(context.getELContext(), "#{myBean.myProperty}", String.class);
    myComponent.setValueExpression("value", vex);
    ValueExpression rex = context.getApplication().getExpressionFactory().createValueExpression(context.getELContext(), "#{myBean.myProperty}", Boolean.class);
    myComponent.setValueExpression("rendered", rex);
    

    MethodBinding – 1.1.5

    MethodBinding methodBinding = FacesContext.getCurrentInstance().getApplication().createMethodBinding(
    			"#{myHandler.action}",null);
    myComponent.setAction( methodBinding );
    

    MethodExpression – 1.2.3

    FacesContext context = FacesContext.getCurrentInstance();
    MethodExpression methodEx = context.getApplication().getExpressionFactory().createMethodExpression(context.getELContext(),
    			"#{myHandler.action}", String.class, new Class[] {});
    myComponent.setActionExpression(methodEx );
    

    ActionListener – 1.1.5

    try
            {    Class[] parameterList = { Class.forName("javax.faces.event.ActionEvent") };
                MethodBinding actionListenerBinding = FacesContext.getCurrentInstance().getApplication().createMethodBinding(
                    "#{myHandler.myListener}",parameterList);
                myComponent.setActionListener(actionListenerBinding );
            }
            catch (Exception e)
           {
                log.error("error setting ActionListener");
            }
    

    ActionListener – 1.2.3

    FacesContext context = FacesContext.getCurrentInstance();
    ELContext elContext = context .getELContext();
    MethodExpression actionListenerExpression = context.getApplication().getExpressionFactory().createMethodExpression(
    elContext,"#{myHandler.myActionListenerMethod}",null,new Class[] {ActionEvent.class});
    
     MethodExpressionActionListener methodExpressionActionListener = new MethodExpressionActionListener(actionListenerExpression);
    
  4. Also rememeber that the tld respects the html 4 specification, so old attribiutes like align, alt, background and color are deprecated. You need to update these and set proper css instead.

Good luck!

Using WebAuthentication in Jboss

Hi!

Because of a respone to my blog post Perform programmatic logon I decided to provide a bit more complete example of how to use the jboss WebAuthentication. I will show how to do the logon in two ways, by an action in a handler and
by doing it in a servler. Logging in by executing an action in a handler could be nice in cases where you have a page that is open to the public, but if you log in you get access
to more information or features.

First I provide an example of a login-config that I’ve tested and used successfully with the WebAuthentication method,

<application-policy name = "myApplication">
      <authentication>
      <login-module code = "org.jboss.security.auth.spi.DatabaseServerLoginModule" flag = "required">
        <module-option name = "dsJndiName">java:/myDatasource-ds</module-option>
        <module-option name = "principalsQuery">Select password from user_table where user_name =?</module-option>
        <module-option name = "rolesQuery">Select 'user', 'Roles', 'RoleGroups' from user_table where user_name =?</module-option>
        <module-option name ="hashAlgorithm">md5</module-option>
        <module-option name="hashEncoding">hex</module-option>
        <module-option name="debug">false</module-option>
     </login-module>
     <login-module code="org.jboss.security.ClientLoginModule" flag="required" />
     </authentication>
 </application-policy>

Create a LoginHandler or something similar, with a method login() and two helper-methods getRemoteUser and getUserPrincipal. Something like this:

public class LoginHandler
{

public String login()
{
        WebAuthentication webAuthentication = new WebAuthentication();

        String hardcodedUserName = "user@somewhere.com";
        String hardcodedPassword = "user123";

        if (webAuthentication.login(hardcodedUserName, hardcodedPassword))
        {
           System.out.println("Logged in successfully");;

            log.debug("userPrincipal: " + getUserPrincipal());
            log.debug("remoteUser: " + getRemoteUser());
        }
        else
        {
            log.debug("Login failed");
        }

        return "";
}
public String getUserPrincipal()
{
        FacesContext context = FacesContext.getCurrentInstance();
        ExternalContext externalContext = context.getExternalContext();
        return externalContext.getUserPrincipal() != null ? externalContext.getUserPrincipal().toString() : "null";
}

public String getRemoteUser()
{
        FacesContext context = FacesContext.getCurrentInstance();
        ExternalContext externalContext = context.getExternalContext();
        String remoteUser = externalContext.getRemoteUser();
        return remoteUser;
}

}

For this example we basically hardcode the username/password, and just test if we get login to work. You should of course use a page and navigation-rules or smth similar to set the username/password as properties in the loginHandler.
Then create a simple jsp, but don’t put it inside your protected folder. Create it one level up so that you can access it without being asked to log in.

In this jsp you will have a stupid commandButton, as well as two outputs that displays the remoteUser and userPrincipal:

<f:view >
    <t:document>
    <t:documentHead>
       <f:loadBundle basename="MessageResources" var="messages" />
    </t:documentHead>

    <f:verbatim>
        <body>
    </f:verbatim>
    <h:form>
        <h:panelGrid>
            <h:commandButton value="Login" action="#{loginHandler.login}"></h:commandButton>
            <h:outputText value="User Principal: #{loginHandler.userPrincipal}"></h:outputText>
            <h:outputText value="Remote User: #{loginHandler.remoteUser}"></h:outputText>
        </h:panelGrid>
    </h:form>
    <f:verbatim>
        </body>
    </f:verbatim>
    </t:document>
</f:view>

Now, launch your application by going to this page. You will see that userPrincipal shows “null” and remoteUser is empty. Press the Login button.
When the page reloads it should display your username in both outputTexts. If you check your log or console it should say “Logged in successfully.”
The user is now properly set in the web container. Also, if you now try to change the url to go to one of your protected pages,
you should not be redirected to any login.jsp, but the page should display properly – because you are already logged on.

Then, to do the logon from a servlet there’s really not a big difference. I set up my web.xml to use a FORM-based logon, like this:

<login-config>
    <auth-method>FORM</auth-method>
    <form-login-config>
     <form-login-page>/login.faces</form-login-page>
     <form-error-page>/loginFailed.faces</form-error-page>
    </form-login-config>
   </login-config>

I also register my LoginServlet in web.xml like this:

<servlet>
    <servlet-name>LoginServlet</servlet-name>
    <servlet-class>com.test.servlet.LoginServlet</servlet-class>
  </servlet>

  <servlet-mapping>
    <servlet-name>LoginServlet</servlet-name>
    <url-pattern>/LoginServlet</url-pattern>
  </servlet-mapping>

My login.jsp is 99% the same as when using j_security_check, we just point the action to the LoginServlet instead:

<form method="POST" name="loginform" action="${pageContext.request.contextPath}/LoginServlet">
<table style="vertical-align: middle;">
<tr>
<td>Username:</td>
<td><input type="text" name="j_username"/></td>
</tr>
<tr>
<td>Password:</td>
<td><input type="password" name="j_password"/></td>
</tr>
<tr>
<td><input type="submit" value="Login" /></td>
</tr>
</table>
</form>

My LoginServlet uses the parameters that was originally passed to the j_security_check. Also, if we successfully log on, we get the “Referer” from the request to redirect to the page that originally was the target for the user. I did not include the code that handles if the logon failed here:

public class LoginServlet extends HttpServlet
{
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException
    {
        // TODO Auto-generated method stub
        doPost(req, resp);

    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException
    {
        String user = req.getParameter("j_username");
        String pass = req.getParameter("j_password");
        WebAuthentication webAuthentication = new WebAuthentication();
        if(    webAuthentication.login(user, pass))
        {
            String redirectUrl = "";
            String referer = req.getHeader("Referer");
            resp.sendRedirect(redirectUrl);
            return;
        }
        else
        {
            System.out.println("Login attempt failed " + user);
            ...
            Handle incorrect logon, go back to login page etc
            ...
        }
    }
}

So, to test this, start your application by pointing directly to some page that is protected. Your login.jsp should be presented, and when you press Login
the servlet uses the credentials you passed in the forms, authenticates and redirect you to the page.
For debug reasons you could add the same outputTexts here on this page (remoteUser and userPrincipal), and they SHOULD show the user you logged in with now.
There is also no problem to navigate to other protected pages.

Hope that these examples might help anybody that struggles with this!

Jaas authentication mechanism – is it possible to force j_security_check to go to a specific page?

A proper answer to my question in the title would be – no. There are no good solutions of doing this, and even if you can come up with something that would work there are always black holes and pits to fall in that are difficult to handle. Not to mention that if you do manage to do something it should be considered a hack rather than a soluton. Still, there are things that can be done, and I will show an example here. But please have in the back of your head what I’ve just said, this is not a fool-proof solution.

The way Jaas works is that you specify some protected resources like this in your web.xml:

 <security-constraint>

  <web-resource-collection>
   <web-resource-name>PROTECTED AREA</web-resource-name>
   <description>Require users to authenticate</description>
   <url-pattern>/pages/protected/*</url-pattern>
  </web-resource-collection>

And then, if you try to send a request or get a page that is protected, JAAS brings up the login for you. This can be either BASIC (which means that a dialog box of your browser will be rendered), or FORM based, where you can specify your login pages like this:

   <login-config>
    <auth-method>FORM</auth-method>
    <form-login-config>
     <form-login-page>/myLoginPage.faces</form-login-page>
     <form-error-page>/myLoginFailed.faces</form-error-page>
    </form-login-config>
   </login-config>

[/sourceode]

The form you use to login would be something like this:


<form method="POST" name="loginform" action="j_security_check">
                        <table style="vertical-align: middle;">
                        <tr><td>Username:</td><td><input type="text" name="j_username"/></td></tr>
                        <tr><td> Password:</td><td><input type="password" name="j_password"/></td></tr>
                       <tr><td><input type="submit" value="Login" /></td></tr>

If you successfully login, JAAS will forward you to the page you initially requested. If your login fails, it will bring up the loginFailed page (if you used FORM method).This works quite well, but there can be situations where you would like the user to always go to the same page when logging in, or even select which page to go to BEFORE logging in. My example let’s you handle this, up to some point at least. As I said initially, there are no good solutions to do this.But to simplify, let’s say that we use FORM based login, and in our login page the user can select whether he/she wants to go to page A or page B. We will use radio-boxes to let the user choose between this. To give you an idea about the flow we want to follow I wil lgive you a brief overview:

  • First, when starting or logging in to our application, the url have to go to a fixed protected page, let’s call it navigation.jsp e.g. When we try to reach this page, JAAS will trigger our authentication form.
  • We don’t set the action of our login form to “j_security_check,” but to a servlet called Login.
  • When we press Login, the servlet gets the username, password and selectedPage from the request.
  • The servlet then builds up a redirectUrl, sets it in the session, but redirects to j_security_check and passes the username and password as parameters.
  • J_security_check will approve our logon, and will forward us to the initial requested page (navigation.jsp)
  • In navigation jsp, we get the session parameter, and then redirect again. The user is now at the page he/she selected.

The form we will use to log on will in other words be something like this:


		<form method="POST" name="loginform" action="/Login">
                        <table style="vertical-align: middle;">
 			<tr><td>Username:</td><td><input type="text" name="j_username"/></td></tr>
                         <tr><td>assword:</td><td><input type="password" name="j_password"/></td></tr>
                       		<td>A</td><td><input type="radio" name="targetPage" value="a" checked="checked" /> </td>
                         <td>B</td><td><input type="radio" name="targetPage" value="b" /> </td>
        	                 <tr><td><input type="submit" value="Login" /></td></tr>
 		</table>
 	</form>

We see that the radio button with value ‘a’ is checked by default, and that the action now points to our servlet instead. Our servlet would be something like this:


public class Login extends HttpServlet
{
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException
    {
        doPost(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException
    {
        String target = req.getParameter("targetPage");
        String user = req.getParameter("j_username");
        String pass = req.getParameter("j_password");

        String redirectUrl = "";

        if(target.equalsIgnoreCase("a"))
             redirectUrl = "TheUrlWeWantToGoToForPageA";
        else if(target.equalsIgnoreCase("b"))
            redirectUrl = "TheUrlWeWantToGoToForPageB";
        else
            redirectUrl = "SomeDefaultPageJustInCaseSomethingHappens";

        req.getSession().setAttribute("redirectUrl", redirectUrl);
        resp.sendRedirect("j_security_check?j_username="+user+"&j_password="+pass);
        return;
    }
}

And our navigation page which will handle the redirection based on the user’s selection is very plain and simple:


<%
    String url = (String)request.getSession().getAttribute("redirectUrl");
    response.sendRedirect(url);
%>

If you have made it this far, you should be able to do a logon to your application, and be forwarded to the page you selected in the login form. But let’s say the login failed, you passed some wrong credentials, the way it is now it would bring up a blank page because it’s the login servlet that is “in control.” In other words, we need to do some more manual work in the login servlet before we pass things on to the security check. If the wrong username or password was entered, we should also give the user a note about this, so we will add some functionality to our login page to display potential messages returned from the login servlet.First we modify our login page to get a statusMessage from the request, and if it is not empty, we display it. Before the login-form itself we add this code:

 <%

String statusMessage= "";

statusMessage = (String)request.getSession().getAttribute("statusMessage");
request.getSession().removeAttribute("statusMessage");

boolean renderMessage = false;
if(StringUtils.isNotBlank(statusMessage))
 renderMessage = true;

%>

Then at the bottom of this login page we add some code to display the message (if it’s there):

 <%
 if(renderMessage)
 {
%>
 <table align="center" width="35%">
 <tr>
 	<td>
 		<table align="center">
 			<tr>
 				<td>
 				<%= statusMessage %>
 				</td>
 			</tr>
 		</table>
 	</td>
 </tr>
 </table>
<%
 }
%>

Then we also add some tests in our servlet to detect different “cases” that might arise. Note that to do this properly you would need some methods that could give you information from the database or the security domain you use. For simplicity I imagine I have a class DBHelper that provides me some utility methods:


public class Login extends HttpServlet
{
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException
    {
        doPost(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException
    {
        String target = req.getParameter("targetPage");
        String user = req.getParameter("j_username");
        String pass = req.getParameter("j_password");

        String redirectUrl = "";
        String statusMessage = "";

        DBHelper dbHelper = new DBHelper();

        //Test if user exists
        if(dbHelper.doesTheUserExist(user))
        {
            //To avoid blank screen on wrong password test if password is valid
            if(dbHelper.isThePasswordCorrect(user, pass))
            {
                        if(target.equalsIgnoreCase("a"))
                            redirectUrl = "TheUrlWeWantToGoToForPageA";
                        else if(target.equalsIgnoreCase("b"))
                            redirectUrl = "TheUrlWeWantToGoToForPageB";
                        else
                            redirectUrl = "SomeDefaultPageJustInCaseSomethingHappens";

                        req.getSession().setAttribute("redirectUrl", redirectUrl);
                        resp.sendRedirect("j_security_check?j_username="+user+"&j_password="+pass);
                        return;
            }
            else
            {            statusMessage = "The login failed - combination of username/password is invalid. Please try again.";
                        redirectUrl = Configurator.getInstance().getHost()+"/"+Configurator.getInstance().getContextRoot()+"/login.faces";
            }
        }
        else
        {
            statusMessage = "The user you tried to log on with doesn't exist.";
            redirectUrl = Configurator.getInstance().getHost()+"/"+Configurator.getInstance().getContextRoot()+"/login.faces";
        }

        //If we reach this point we should go back to the login page. We also set the status message to explain to the user.
        req.getSession().setAttribute("callbackMessage", callbackMessage);
        resp.sendRedirect(redirectUrl);
    }
}

Ok, as I said in the beginning this “solution” should not be considered a proper one, passing the credentials through the parameter string e.g. is not actually a good way of doing things. But I’ll leave that for you to decide..πŸ˜‰