Home > Java EE > Servlet 3 Programmatic Authentication API

Servlet 3 Programmatic Authentication API

Servlet 3 introduces a new, more logical and easy to use API for doing programmatic authentication. It is a long-waited change by many developers. Before (without dealing with JAAS directly) the only choice was an old FORM authentication method, which is not flexible enough. It puts constraints on html markup making the method incompatible or difficult to use in some frameworks. Now you can easily use login(String username, String password) and logout() method pair declared on HttpServletRequest. It is definitely a nice step forward, but it worth to mention that it is still limited to a password-based authentication only. If you plan to use other authentication methods, you still have to deal with JAAS directly.
Below is a sample code. It is based on CDI (JSR-299), which is a part of Java EE 6. It is also assumes JSF 2 used as web framework.

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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
@Named
@RequestScoped
public class Authenticator {
 
	private String username;
	private String password;
 
        /**
         * Performs authentication via HttpServletRequest API
         */
	public boolean authenticate() {
		if (!isAuthenticated()) {
			try {
				getRequest().login(username, password);
			} catch (ServletException e) {}
		}
		return isAuthenticated();
	}
 
        /**
         * Logs out using HttpServletRequest API
         */
	public void logout() throws ServletException {
		if (isAuthenticated())
			getRequest().logout();
		return null;
	}
 
	public boolean isAuthenticated() {
		return getRequest().getUserPrincipal() != null;
	}
 
	public boolean isUserInRole(String role) {
		return getRequest().isUserInRole(role);
	}
 
	public Principal getPrincipal() {
		return getRequest().getUserPrincipal();
	}
 
	private HttpServletRequest getRequest() {
		FacesContext facesContext = FacesContext.getCurrentInstance();
		ExternalContext externalContext = facesContext.
                         getExternalContext();
		Object request = externalContext.getRequest();
		return request instanceof HttpServletRequest ? 
                        (HttpServletRequest) request : null;
	}
 
	public String getUsername() {
		return username;
	}
 
	public void setUsername(String username) {
		this.username = username;
	}
 
	public String getPassword() {
		return password;
	}
 
	public void setPassword(String password) {
		this.password = password;
	}
 
}

The code is trivial. Authenticator is a CDI managed bean. You can @Inject it to other managed beans, or reference by name from JSF 2 EL expressions. The sample relies on FacesContext being available so it will not work immediately when invoked from servlet filters, listeners, etc.
The last thing I would like to warn you about is that Glassfish v3, which is a reference implementation of Java EE 6, have a bug in the HttpServletRequest.login method implementation. It does not store authentication state in a session as it should. The bug planned to be resolved in Glasfish 3.0.1. For now, the workaround is to store credentials in session and perform authentication on each request.

Categories: Java EE Tags: , , ,
  1. Ryan
    February 23rd, 2011 at 21:22 | #1

    I’ll have to give this a try since there are issues with CDI and form-based authentication in GlassFish:

    http://java.net/jira/browse/GLASSFISH-12642

  2. FĂ«anor
    February 28th, 2011 at 18:59 | #2

    Thanxs, it helped ;)

  3. Martin
    February 7th, 2012 at 12:44 | #3

    Hi,

    I have an J EE 6, JSF 2, JPA, CDI, JBoss AS 7.0.2 web app…. When I try to call getRequest().login Im getting

    javax.servlet.ServletException: No authenticator available for programmatic login

    I googled around, but I could not find out how to make an authenticator available. Do you have an idea?

    Thanks

  4. Anonymous
    December 29th, 2013 at 22:24 | #4

    Thanks a lot.

  1. No trackbacks yet.