Tuesday Mar 30, 2010

Authentication Without the Form

The nice thing about form-based authentication is that it allows a simple way for an application to let the container handle common security tasks. The bad thing about it is that, well, you need an HTML form. For a "Rich Internet Application" (RIA) that doesn't normally use JSPs or HTML pages, this means tacking on some extra files that don't have a natural fit in your application: the JSPs and/or HTML pages themselves, along with a deployment descriptor to specify the security settings. With the new features of the Servlet 3.0 spec, form-based login is no longer needed. Instead, your application can collect username and password credentials however you'd like and simply pass them to the container during an HTTP request. (Logout is equally simple.)

With form-based authentication, you would normally select some set of URLs and protect them with a security constraint. To access these URLs, a user would have to be authenticated and properly authorized. In some RIAs, this pattern no longer makes sense. For example, there may be few (or one) URL for the entire application. Instead, you can apply declarative security at the EJB level to protect any sensitive information (remember that EJBs can be used within a war file in Java EE 6!)

In this blog, I'll show an example of user authentication that doesn't involve an HTML form (or any JSP or HTML pages). There is a simple session bean acting as our back end service, and one of the two "hello world" style methods can only be called by a caller in the 'ADMIN' role:

    @RolesAllowed("ADMIN")
    public String getAdminMessage() {
        return String.format("Hello again '%s', it's great to see you!",
            context.getCallerPrincipal().getName());
    }

While the entire application is available in this zip file, you can see the full session bean, copiously commented, here. The rest of the sample application is simple as well: there is a main, servlet-based application class using Vaadin that includes these two panels (the authentication panel has been broken out into a separate class). See the code in the authentication panel for the full details, but the code to log the user in is this simple:

    String name = // retrieved from web UI
    String pass = // retrieved from web UI
    
    // exception handling omitted here
    // app.getRequest() returns the current HttpServletRequest
    app.getRequest().login(name, pass);

Logging the user out, of course, uses the logout() method instead. Here is the full user interface:

The ee6auth example application

In the "Actions" panel, there are two buttons that call a method in the EJB when clicked. The top button can be used whether there is an authenticated user or not. The other will result in an exception if there is not an authenticated user who is authorized to make the call (a user in the 'ADMIN' role). The exception is popped up in the browser to let you know what happened. Please see the three class files for comments describing the details of each part of the application. Note: while we're keeping this example simple, remember to use SSL any time you're dealing with user credentials such as passwords. The only other file in the application is a deployment descriptor that maps users in the authentication realm to the proper application role.

Before using the application, you need to add some users in the proper group in the default realm in the application server. The group we're using is 'ADMIN_GROUP,' but you can use any group you'd like as long as the mapping is correct in sun-web.xml. To help get you set up, here is a screen cast that shows how to create users in the default realm in GlassFish. We're keeping this very simple by using the file realm in the server, but you could use any realm you'd like. To use a realm other than the default one, add a web.xml file to specify it:

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
    <login-config>
        <realm-name>your-realm-here</realm-name>
    </login-config>
</web-app>

Important note: because of this issue, you need a post-3.0 build of GlassFish v3. You can download a promoted build of v3.0.1 here -- to install, just unzip it. One more time, here's a link to the example application.

To build the application, you can use any IDE that supports Maven or use the command 'mvn clean package' to build it directly. Then deploy with the admin console or use this command (the --force option is only necessary on the 2nd or later deployment):

asadmin deploy --force --contextroot /ee6a <somepath>/ee6auth/target/ee6auth.war

Then you can access the application in a browser with http://localhost:8080/ee6a/. Let me know if you have any problems with the example. For any general questions, you'll get an answer more quickly at users@glassfish.dev.java.net.

I'd like to give a big thanks to Petter Holmström from the Vaadin team for his help, especially the article Creating Secure Vaadin Applications Using JEE6 that explains the steps needed to use regular form-based authentication (and a lot more) with a Rich Internet App such as Vaadin.

Thursday Jul 02, 2009

RIA without XML

One of the cool things I discovered at JavaOne this year was a framework for building rich internet applications (RIAs) called Vaadin. Besides being a very nice tool, they also had the good idea of giving away printed copies of their free book at the booth. Since my laptop battery time is limited, having a hard copy to read gave me plenty of time to learn about it between sessions, while waiting to meet people, while sitting at the bar, etc.

Vaadin is a web application framework that lets you write Java code to create your web pages. No JSP, no HTML (unless you want to), no XML, etc., and only one jar file needed for the framework. Somewhere in my reading or while talking to one of the Vaadin people, I came across the one exception to the "no xml" statement: Vaadin is still a Java EE application, so of course there is still a web.xml file needed to deploy an application. My first thought was, "We can fix that, right?" So for no particular reason, here is how to create a rich internet application with no XML files at all using Vaadin and Servlet 3.0 inside GlassFish v3 Preview.

To get rid of the web.xml file, use the @WebServlet annotation on your servlet class. Vaddin is open-source, so of course you could add it to the class and rebuild it. But let's do the proper thing and subclass the servlet. I've put it in the same package as the parent in case it's looking for any resources relative to the package. Here is the entire class:

package com.vaadin.terminal.gwt.server;

import javax.servlet.annotation.WebInitParam;
import javax.servlet.annotation.WebServlet;

@SuppressWarnings("serial")
@WebServlet(
    name = "Noxml Application",
    initParams = {
        @WebInitParam(name = "application",
            value = "com.example.noxml.NoxmlApplication")
        },
    urlPatterns = { "/\*" }
)
public class EE6ApplicationServlet extends ApplicationServlet {
    // nothing here
}

Pretty simple stuff. Thank you Servlet 3.0. Now, to give you a sense of what Vaadin is like and to show that this really works, here is the application I wrote. It simply adds a couple blocks of text to the web page and a button. Clicking the button switches the text between the two lines (called "labels" in Vaadin). Here is the entire class:

package com.example.noxml;

import com.vaadin.Application;
import com.vaadin.ui.\*;
import com.vaadin.ui.Button.ClickEvent;

@SuppressWarnings("serial")
public class NoxmlApplication extends Application {	
    /\*
     \* A very simple application with two labels and a button.
     \* To keep this short, I've added an anonymous listener
     \* for the button that calls my very exciting swap method.
     \*/
    @Override
    public void init() {
        // create components
        Window mainWindow = new Window("Noxml Application");
        final Label label1 = new Label("Hello RIA.");
        final Label label2 = new Label("Goodbye XML.");
        Button button = new Button("Very Exciting Button",
            new Button.ClickListener() {
                public void buttonClick(ClickEvent event) {
                    swapText(label1, label2);
                }
            });

        // add 'em
        mainWindow.addComponent(label1);
        mainWindow.addComponent(button);
        mainWindow.addComponent(label2);

        // add window to the application
        setMainWindow(mainWindow);
    }

    // where is my tuple unpacking?
    private void swapText(Label l1, Label l2) {
        Object temp = l1.getValue(); // a string in this case
        l1.setValue(l2.getValue());
        l2.setValue(temp);
    }
}

That's all there is to it. My entire web application contains only three classes (one is the anonymous inner class in NoxmlApplication), a single jar file in the lib directory, and no xml files. It's not much to look at since I kept it simple, but all of the Ajax requests/responses are taken care of for me and I just wrote a little Java code. Speaking of not much to look at, here is a very exciting screen cast of the web application in action.

I've included the Vaadin links above. If you'd like to try out GlassFish v3 and the great developer features of Java EE 6, here are some instructions on setting up the application server with NetBeans and with Eclipse (the latter only shows v3 Prelude, but you can use a v3 server as well). For more on creating a servlet using the 2.0 annotations, see Arun's blog. Have fun.

About

Whatever part of GlassFish or the Java EE world that catches my attention. (Also, go Red Sox.)

Search

Categories
Archives
« April 2014
SunMonTueWedThuFriSat
  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
   
       
Today