Once in a while one stumbles upon an error message like this

java.lang.ClassFormatError: Absent Code attribute in method that is not native or abstract in class file javax/mail/Session

This happens if your code compiles against incomplete classes, like the JavaEE6 Api and your Unit tests try to access code thats not there. JUnit will simply fail and mark the test as error, printing something like this

Tests in error: 
  initializationError(com.dominikdorn.dc.passwordReset.SimplePasswordResetServiceTest)

and the corresponding surefire text file starts like this:

-------------------------------------------------------------------------------
Test set: com.dominikdorn.dc.passwordReset.SimplePasswordResetServiceTest
-------------------------------------------------------------------------------
Tests run: 1, Failures: 0, Errors: 1, Skipped: 0, Time elapsed: 0.022 sec <<< FAILURE!
initializationError(com.dominikdorn.dc.passwordReset.SimplePasswordResetServiceTest)  Time elapsed: 0.005 sec  <<< ERROR!
java.lang.ClassFormatError: Absent Code attribute in method that is not native or abstract in class file javax/mail/Session
        at java.lang.ClassLoader.defineClass1(Native Method)
        at java.lang.ClassLoader.defineClass(ClassLoader.java:621)
        at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:124)
        at java.net.URLClassLoader.defineClass(URLClassLoader.java:260)
        at java.net.URLClassLoader.access$000(URLClassLoader.java:56)
        at java.net.URLClassLoader$1.run(URLClassLoader.java:195)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.net.URLClassLoader.findClass(URLClassLoader.java:188)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:307)
....

The Solution
You have to compile against real-implementations of the classes. You do that by adding those dependencies before the most generic dependency in your pom.xml

As example, we add javax.mail BEFORE javaee6-api like this

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<project ...>
...
    <dependencies>
 
        <dependency>
            <groupId>javax.mail</groupId>
            <artifactId>mail</artifactId>
            <version>1.4</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>javax</groupId>
            <artifactId>javaee-api</artifactId>
            <version>6.0</version>
            <scope>provided</scope>
        </dependency>
</project>

If you are deploying your App on an Appserver like Glassfish or JBoss AS, leave the scope of javax.mail:mail as provided to prevent the inclusion of the jar in the final webapp.

I now list required dependencies for various Absent Code Errors I've encountered and still encountering. This post will be updated every time I solve another of these problems.

JavaMail: javax/mail/Session

1
2
3
4
5
6
7
8
9
10
11
<project ...>
...
    <dependencies>
        <dependency>
            <groupId>javax.mail</groupId>
            <artifactId>mail</artifactId>
            <version>1.4</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>
</project>

Servlet 3.0

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<project ...>
...
    <dependencies>
               <dependency>
                       <groupId>org.glassfish</groupId>
                       <artifactId>javax.servlet</artifactId>
                       <version>3.0</version>
                       <scope>provided</scope>
               </dependency>
...
    </dependencies>
....   
    <repositories>
               <!-- Required until the Servlet 3.0 API can be resolved in Central -->     
               <repository>
                       <id>Glassfish</id>
                       <name>Glassfish Maven2 Repository</name>
                       <url>http://download.java.net/maven/glassfish/</url>
               </repository>
    </repositories>
 </project>

JPA2: javax/persistence/PersistenceException

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<dependencies>...
        <dependency>
            <groupId>org.eclipse.persistence</groupId>
            <artifactId>javax.persistence</artifactId>
            <version>2.0.0</version>
            <scope>provided</scope>
        </dependency>
...</dependencies>
..
<repositories>
...
    <repositories>
...
        <repository>
            <id>eclipse</id>
            <name>Eclipse Maven Repository</name>
            <url>http://www.eclipse.org/downloads/download.php?r=1&amp;nf=1&amp;file=/rt/eclipselink/maven.repo</url>
        </repository>
    </repositories>

JAX-RS: javax/ws/rs/core/UriBuilder

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
        <dependency>
            <groupId>com.sun.jersey</groupId>
            <artifactId>jersey-core</artifactId>
            <version>1.1.5</version>
            <scope>provided</scope>
        </dependency>
<!-- for json support -->
        <dependency>
            <groupId>com.sun.jersey</groupId>
            <artifactId>jersey-json</artifactId>
            <version>1.1.5</version>
            <scope>provided</scope>
        </dependency>
<!-- for testing --> 
        <dependency>
            <groupId>com.sun.jersey</groupId>
            <artifactId>jersey-test-framework</artifactId>
            <version>1.1.5.1</version>
            <scope>test</scope>
        </dependency>

more to come soon!

In XHTML strict, the ol-tag does not have the attribute start.

To get this working again, simply create a css-class

1
2
.counterList li {display: block }
.counterList li:before {content: counter(start) ". "; counter-increment: start}

and surround your list with a tag like this

1
2
3
4
5
6
7
<div class='counterList>
<ol style="counter-reset: start 4">
<li>this will be item 5</li>
<li>this will be item 6</li>
...
</ol>
</div>

I got this idea from http://www.timrivera.com/tests/ol-start.html

So, you’re ended up in a situation, where you are somewhere (e.g. a javax.faces.Converter) where you are unable to simple @Inject SomeClass ?

I had the problem, that I had a FacesConverter like this:

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
import javax.annotation.ManagedBean;
import javax.annotation.PostConstruct;
import javax.enterprise.context.RequestScoped;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.convert.Converter;
import javax.faces.convert.FacesConverter;
import javax.inject.Inject;
 
 
@FacesConverter(forClass = AvailableCountry.class)
@ManagedBean // does not help :(
@RequestScoped // does not help :(
public class AvailableCountryConverter implements Converter
{
	@Inject
	AvailableCountryDao dao;
 
	@PostConstruct
	public void postConstruct()
	{
		System.out.println("calling postConstruct");
	}
 
	public Object getAsObject(FacesContext facesContext, UIComponent
			component, String value) {
		if (value == null || value.length() == 0) {
			return null;
		}
		return dao.find(getKey(value));
	}
 
	Long getKey(String value) {
		Long key;
		key = Long.valueOf(value);
		return key;
	}
 
	String getStringKey(long value) {
		StringBuffer sb = new StringBuffer();
		sb.append(value);
		return sb.toString();
	}
 
	public String getAsString(FacesContext facesContext, UIComponent
			component, Object object) {
		if (object == null) {
			return null;
		}
		if (object instanceof AvailableCountry) {
			AvailableCountry o = (AvailableCountry) object;
			return getStringKey(o.getCountry().getId());
		} else {
			throw new IllegalArgumentException("object " + object + "
					is of type " + object.getClass().getName() + "; expected type: " +
					AvailableCountry.class.getName());
		}
	}
}

But my DAO was not injected, nor was the postConstruct method triggered by CDI.

Why?
Because the bean is not managed by CDI, not even when annotating it with @ManagedBean because it gets created by the JSF-Lifecycle and not by CDI.

Well.. but how to manually lookup a Bean with CDI / Weld?

First, you need to get the BeanManager. When you have a FacesContext (like in the converter above), you can get it like this:

1
2
3
4
5
6
    public BeanManager getBeanManager()
    {
        return (BeanManager) 
              ((ServletContext) facesContext.getExternalContext().getContext())
                   .getAttribute("javax.enterprise.inject.spi.BeanManager"); 
    }

If you don’t have access to a FacesContext, ServletContext or similar, you can lookup the BeanManager through JNDI

1
2
3
4
5
6
7
8
9
10
    public BeanManager getBeanManager()
    {
        try{
            InitialContext initialContext = new InitialContext();
            return (BeanManager) initialContext.lookup("java:comp/BeanManager");
        catch (NamingException e) {
            log.error("Couldn't get BeanManager through JNDI");
            return null;
        }
    }

After you’ve got your BeanManager, simply lookup your Bean like this:
(In my case, I wanted to lookup a bean with the type AvailableCountryDao)
Type-based CDI manual lookup

1
2
3
4
5
6
7
8
    public AvailableCountryDao getFacade()
    {
        BeanManager bm = getBeanManager();
        Bean<AvailableCountryDao> bean = (Bean<AvailableCountryDao>) bm.getBeans(AvailableCountryDao.class).iterator().next();
        CreationalContext<AvailableCountryDao> ctx = bm.createCreationalContext(bean);
        AvailableCountryDao dao = (AvailableCountryDao) bm.getReference(bean, AvailableCountryDao.class, ctx); // this could be inlined, but intentionally left this way
        return dao;
    }

Thanks to my friend Lincoln Baxter, III for the snipped.

Name-based CDI manual lookup

1
2
3
4
5
6
7
8
    public Object getBeanByName(String name) // eg. name=availableCountryDao
    {
        BeanManager bm = getBeanManager();
        Bean bean = bm.getBeans(name).iterator().next();
        CreationalContext ctx = bm.createCreationalContext(bean); // could be inlined below
        Object o = bm.getReference(bean, bean.getClass(), ctx); // could be inlined with return
        return o;
    }

So, now you’re able to manually lookup beans with CDI.
In case you have the same problem (with Converters/Validators) like I had above, checkout Seam Faces, where this problem already is fixed,
meaning your @ManagedBean annotated Converter/Validator is working as expected with @Inject, @PostConstruct & @PreDestroy 🙂

If you – like me – have the problem, that you need to run Tomcat or Glassfish or any other Java Webserver on Port 80, this might come handy for you:

The problem:
Tomcat, Jetty, Glassfish, JBoss AS etc. .. they all run on unprivileged ports > 1024, defaulting to 8080.

If you want to run them on port 80, you have several choices:
– front them with Apache
– front them with Squid
– use some tools like authbind, etc.
– use IPTables magic (which we will describe here)

Primitive IPTables solution:
This solution comes from the blog entry ” Installing Tomcat on port 80 with iptables
You have to compile NAT support into your kernel and use an iptables rule like this one

iptables -t nat -I PREROUTING --src 0/0 --dst $yourip -p tcp --dport 80 -j REDIRECT --to-ports 8080

which redirects all incoming traffic on port 80 on $yourip (e.g. 74.125.39.99) to port 8080 on the local machine.
If your webserver listens only to 127.0.0.1 this is all you need to be save.

However, I have a bit a different setup:

– Two networks with different providers (4mbit e.g. 74.125.39.99, 12mbit e.g. 98.137.149.56 )
– Two servers, one of them quite small powered (pentium4 on the 4mbit line), the other quite strong (dual quad core 2ghz on the 12mbit line)
– Glassfish on the strong server
– DNS load balancing for the domain
– both servers should map to the same glassfish instance.
– the servers are connected through a direct link with private IP-addresses (10.x.x.x range)
– Glassfish binds only to the private IP-Address of the strong server, meaning 10.0.100.10:8080
– both 74.125.39.99:80 and 98.137.149.56:80 should redirect the traffic to 10.0.100.10:8080

Here’s how I’ve done it (I got some inspiration from this linux questions forum entry):

On the “strong” server

#this forwards traffic to the internal ip
iptables -A PREROUTING -t nat -d 74.125.39.99/32 -p tcp -m tcp --dport 80 -j DNAT --to 10.0.100.10:8080
#this allows traffic on the external interface on port 80
iptables -A INPUT -d 74.125.39.99/32 -p tcp -m tcp --dport 80 -j ACCEPT
#this allows traffic on the internal ip on port 8080
iptables -A INPUT -d 10.0.100.10/32 -p tcp -m tcp --dport 8080 -j ACCEPT

nearly the same on the “weaker” server

#this forwards traffic to the internal ip
iptables -A PREROUTING -t nat -d 74.125.39.99/32 -p tcp -m tcp --dport 80 -j DNAT --to 10.0.100.10:8080
#this allows traffic on the external interface on port 80
iptables -A INPUT -d 98.137.149.56/32 -p tcp -m tcp --dport 80 -j ACCEPT

That’s it!

Perfectly save, perfectly scalable glassfish v3 (no apache bottleneck in your comet apps!)

As I sometimes need these, I have compiled a list of the valid headers of the web.xml and web-fragment.xml file for servlet version 2.3 until 3.0.
Maybe you find them as handy as I do.

web.xml v2.3

1
2
3
4
5
6
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd">
 
<web-app>
 
</web-app>

web.xml v2.4

1
2
3
4
5
6
<?xml version="1.0" encoding="UTF-8"?>
<web-app id="WebApp_9" version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" 
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
 
</web-app>

web.xml v2.5

1
2
3
4
5
6
7
8
9
10
11
<?xml version="1.0" encoding="UTF-8"?>
 
<web-app 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_2_5.xsd"
 
version="2.5">
 
</web-app>

web.xml v3.0

1
2
3
4
5
6
7
8
9
<?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">
 
</web-app>

web-fragment.xml:

1
2
3
4
5
6
<web-fragment 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-fragment_3_0.xsd" version="3.0">
 
</web-fragment>

If you like to construct complex & pretty urls with JSF2 & PrettyFaces, you might be interested in the following few lines of code.

In our example, we want to match a URL like this one

1
http://www.studyguru.eu/at/tuwien/184.153--Entwurfsmethoden-fuer-verteilte-Systeme

Previously I tried to match it with a PrettyFaces Pattern/Regex like this:

       <pattern value="/([a-z]{2})/([a-z0-9\-_]*)/([a-z0-9\-_\.]*)\-\-.*"/>

But thankfully, PrettyFaces >2.0.4 supports directly populating the RequestParams!

Configure your pretty-config like this:

1
2
3
4
5
6
7
8
9
10
11
<pretty-config xmlns="http://ocpsoft.com/prettyfaces/2.0.4"
               xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
               xsi:schemaLocation="http://ocpsoft.com/prettyfaces/2.0.4
                http://ocpsoft.com/xml/ns/prettyfaces/ocpsoft-pretty-faces-2.0.4.xsd">
....
 
    <url-mapping id="coursePage">
        <pattern value="/#{countryCode}/#{uniShortName}/#{courseId}--.*"/>
        <view-id>/path/to/coursePage.xhtml</view-id>
    </url-mapping>
....

and use JSF2’s viewParams like this:

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
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html
        PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
        "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:f="http://java.sun.com/jsf/core"
      xmlns:pretty="http://ocpsoft.com/prettyfaces"
      xmlns:ui="http://java.sun.com/jsf/facelets"
      xmlns:p="http://primefaces.prime.com.tr/ui"
        >
<body>
<f:metadata>
    <f:viewParam id="countryCodeId"
                 required="true"
                 requiredMessage="Kein Land spezifiziert"
                 name="countryCode" value="#{coursePageBean.countryCode}"
            >
        <f:validateRegex pattern="([a-z]{2})"/>
    </f:viewParam>
 
    <f:viewParam id="universityCodeId"
                 required="true"
                 requiredMessage="Keine Hochschule spezifiziert"
                 name="uniShortName" value="#{coursePageBean.universityCode}"
            >
        <f:validateRegex pattern="([a-z0-9\-_]*)"/>
    </f:viewParam>
    <f:viewParam id="courseIdId"
                 required="true"
                 requiredMessage="Keine KursId spezifiziert"
                 name="courseId" value="#{coursePageBean.courseId}"
            >
        <f:validateRegex pattern="([a-z0-9\-_\.]*)"/>
    </f:viewParam>
 
    <f:event type="preRenderView" listener="#{coursePageBean.populate}"/>
</f:metadata>
<h1>coursePage</h1>
 
countryCode #{ coursePageBean.countryCode} <br/>
courseId #{coursePageBean.courseId}<br/>
universityCode #{coursePageBean.universityCode}<br/>
</body>
</html>

Voila! You now can match complex urls with PrettyFaces and apply all your custom validators
to your Pretty URL 🙂

I’ve noticed that google indexed various pages of mine with appended “;jsessionid=somehash”
Thats not only ugly, but also a security risk.

But how to disable Session Tracking by URL? How to set it to Cookie only ?

Take this!

Update: Jan Luehe showed me a way, how to do this in web.xml only – without a listener

1
2
3
4
5
6
7
 <web-app ...>
    <session-config>
        <tracking-mode>COOKIE</tracking-mode>
        <tracking-mode>URL</tracking-mode>
       <tracking-mode>SSL</tracking-mode>
    </session-config>
 </web-app>

if you prefer to do it programmatically (e.g. when doing a custom web-app configuration wizzard or something like this), do it this way:

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
package com.dominikdorn.dc.listeners;
 
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.SessionTrackingMode;
import javax.servlet.annotation.WebListener;
import java.util.HashSet;
import java.util.Set;
 
/**
 * This Listener sets the tracking modes used by the servletContext
 */
@WebListener(value = "This listener sets the session tracking modes")
public class SetSessionTrackingModeListener implements ServletContextListener {
 
    // Public constructor is required by servlet spec
 
    public SetSessionTrackingModeListener() {
    }
 
    public void contextInitialized(ServletContextEvent sce) {
        Set<SessionTrackingMode> modes = new HashSet<SessionTrackingMode>();
        // modes.add(SessionTrackingMode.URL); // thats the default behaviour!
        modes.add(SessionTrackingMode.COOKIE);
//        modes.add(SessionTrackingMode.SSL); // this works only with client certs.       
        sce.getServletContext().setSessionTrackingModes(modes);
    }
 
    public void contextDestroyed(ServletContextEvent sce) {
    }
 
}

Questions? Comments? Post them here!

A User on the glassfish mailing list posted a question:

I would like to aks it. How must set up ie8 compatibility mode in glassfish?
This is the iis setting:

<system.webServer>
       <httpProtocol>
               <customHeaders>
                       <clear />
                       <add name="X-UA-Compatible" value="IE=EmulateIE7" />
               </customHeaders>
       </httpProtocol>
</system.webServer>

Well… how to do that?

Simply create a Servlet Filter!

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
package com.dominikdorn.dc.filters;
 
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.annotation.WebInitParam;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.logging.Logger;
 
 
@WebFilter(urlPatterns = {"/*"}, initParams = {@WebInitParam(name = "compatibilityMode", value = "IE=EmulateIE7")})
public class UserAgentCompatibleFilter implements javax.servlet.Filter {
    private Logger log = Logger.getLogger("UserAgentCompatibleFilter");
    private String compatibilityMode;
 
    public void destroy() {
    }
 
    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
        if (compatibilityMode != null) {
            HttpServletResponse res = (HttpServletResponse) resp;
            res.addHeader("X-UA-Compatible", compatibilityMode);
        }
        chain.doFilter(req, resp);
    }
 
    public void init(FilterConfig config) throws ServletException {
        compatibilityMode = config.getInitParameter("compatibilityMode");
        if (compatibilityMode == null) {
            log.warning("No CompatibilityMode set for UserAgentCompatibleFilter, thus disabling it");
        }
    }
}

If you’re not using Servlet 3.0, simply comment out the @WebServlet annotation. If you want to customize
the header, add this to your web.xml and modify it, so that it suit your needs.

1
2
3
4
5
6
7
8
9
10
11
12
13
    <filter>
        <filter-name>UserAgentCompatibleFilter</filter-name>
        <filter-class>com.dominikdorn.dc.filters.UserAgentCompatibleFilter</filter-class>
        <init-param>
            <param-name>compatibilityMode</param-name>
            <param-value>IE=EmulateIE7</param-value>
        </init-param>
    </filter>
 
    <filter-mapping>
        <filter-name>UserAgentCompatibleFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

To see if it works, compile and redeploy your app.. you can then test it, e.g. with curl:

curl -D - http://localhost:8080/info.xhtml
HTTP/1.1 200 OK
X-Powered-By: Servlet/3.0
Server: GlassFish v3
Set-Cookie: JSESSIONID=3afbe6498aa3f495e8340d8e67ef; Path=/
X-UA-Compatible: IE=EmulateIE7
X-Powered-By: JSF/2.0
Content-Type: text/html;charset=UTF-8
Content-Length: 2997
Date: Tue, 09 Mar 2010 16:09:03 GMT

Suggestions? Comment here!

The “ironic programmer” published an article, how to create a really basic file upload with jsf2. He has not created any custom tags, but simply added a file-input field in his view and made the server populate a byte-array in his bean.

His post was influenced by Uploading files with JSF 2.0 and Servlet 3.0 by BalusC.

He probably missed our JSF2 FileUpload-Github-Project where the taglib is ready for usage and really simple to integrate.

Still, thumbs up for the nice post!

In the second part of this series, we are going to understand some more terminology of JAAS and start creating our own authentication system.

A LoginContext Object is used by applications to authenticate users independently of the underlying authentication technology. Authentication technology in this context means stuff like “file based authentication”, “Database based authentication”, “LDAP authentication”, “CERTIFICATE authentication” and so on.

The LoginContext class is part of the javax.security.auth.login package and describes methods used to authenticate Subjects/user in the meaning of Part 1 of this series). The documentation states:

A subject is an identity in a system that you want to authenticate and assign access rights to. A subject can be a human user, a process, or a machine..

which is basically what I said before. Its still a little bit unclear to me, why they use “user” in one documentation and “subject” in the other, but as its the same thing, we know what to do.

The documentation further states, that a subject may interact with different authorities (applications) and may have different passwords (credentials) for each of them. To represent the subject/user in these applications, the java.security.Principal class is used.

Our own LoginContext now invokes various LoginModules ( these handle the different ways of authentication, like form based, HTTP-Basic, HTTP-Digest, etc.). The LoginModule interface is part of
the javax.security.auth.spi package. If one ever wants to integrate Facebook connect or something similar, this is where to look at!

But how does the LoginContext know, which LoginModules to invoke? This is done by a Configuration Object.

So, to sum this up:

  1. We have 1-n LoginModules, handling different form of authentication.. file, db, ldap and so on
  2. We have a LoginContext, taking users credentials and supplying them to the LoginModules
  3. We have configurations, specifying which LoginModules should be used by the LoginContext
  4. A client supplies its credentials to the LoginContext. The LoginContext looks up, which LoginModules to use in its Configuration and authenticates the client with the provided credentials against the LoginModules.

But why bother with all this stuff of LoginContext, LoginModules, Configuration and so on? Shouldn’t it be easy to use authentication, especially custom authentication in a web-app?

Because we’ve already got it in our AppServer!

Configuration:
We’re actually creating our Configuration object manually in our web.xml.

Here we define, how we gain the authentication data from the user. In this example, I used auth-method=FORM because no-one wants to use HTTP-Basic Authentication anymore today!

    
        FORM
        nameOfTheRealm
        
            /login.xhtml
            /loginError.xhtml
        
    

With this configuration, you can already create your own login form with your preferred style, like this:
login.xhtml

1
2
3
4
5
<form method="post" action="#{request.contextPath}/j_security_check">
<label for="username">Userid</label><input type="text" id="username" name="j_username">
<label for="password">Password</label><input type="password" id="password" name="j_password">
<input type="submit" value="Login">
</form>

In the next part of the series, we’ll see how you can do it with an jsf/facelets page.

Ok, we now got our form for login. To Logout simply make a link to /j_security_logout

We’ve now got login + logout, but they are not working yet. What we still have to do, is specify, what we’re authenticating against. In this post, we called it LoginModule, in Glassfishv3 its called Realm and we have already
configured it with our Login-Config above.

A post which explains how to configure the simply, build in Glassfish “File-Realm” is available at DevelopInJava.com.

In the next blog entry of this series, we’ll see how we can create our own realm, that really suits our needs.

We now got everything needed for a basic authentication, but we don’t yet have a group to role mapping, which we need for stuff like #{request.isUserInRole(‘ADMIN’)} or annotating our beans (see later for all of that).
So what we’re going to do is, map the given “groups” to roles. Before we do that, we should tell our application, which roles we have. Do it like that in your web.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
    <security-role>
        <description>all the users with the role Admin</description>
        <role-name>ADMIN</role-name>
    </security-role>
 
    <security-role>
        <description>all the users that are authenticated</description>
        <role-name>LOGGEDIN_USER</role-name>
    </security-role>
 
    <security-role>
        <description>all the users that are moderators/extended rights</description>
        <role-name>MODERATOR</role-name>
    </security-role>

Now we can map the groups we get from the realm to our roles. We have to put this in
/WEB-INF/sun-web.xml (if you’re using Glassfish v3). My file looks like this:

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
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE sun-web-app PUBLIC '-//Sun Microsystems, Inc.//DTD 
Application Server 9.0 Servlet 2.5//EN'
    'http://www.sun.com/software/appserver/dtds/sun-web-app_2_5-0.dtd'>
<sun-web-app error-url="">
    <context-root>/</context-root>
    <security-role-mapping>
        <role-name>LOGGEDIN_USER</role-name>
        <group-name>default</group-name>
    </security-role-mapping>
    <security-role-mapping>
        <role-name>MODERATOR</role-name>
        <group-name>moderatoren</group-name>
    </security-role-mapping>
    <security-role-mapping>
        <role-name>ADMIN</role-name>
        <group-name>root</group-name>
    </security-role-mapping>
    <class-loader delegate="true"/>
    <jsp-config>
        <property name="keepgenerated" value="true">
            <description>Keep a copy of the generated 
                servlet class' java code.</description>
        </property>
    </jsp-config>
</sun-web-app>

Click here to view the general structure of the sun-web.xml file.

Our User -> Principal, Group -> Role mapping now works. We can start protecting resources in our app! Horray!

We’re doing this by specifying “security-constraints” like this in our web.xml

1
2
3
4
5
6
7
8
9
10
    <security-constraint>
        <web-resource-collection>
            <web-resource-name>admin-area</web-resource-name>
            <url-pattern>/admin/</url-pattern>
        </web-resource-collection>
        <auth-constraint>
            <description>admins should be allowed to access this resources</description>
            <role-name>ADMIN</role-name>
        </auth-constraint>
    </security-constraint>

This should be quite self-explanatory, for a detailed explanation take a look at
Security Annotations and Authorization in GlassFish and the Java EE 5 SDK, which also explains how to secure beans with annotations
and has a nice matrix whats possible with annotations and whats not.

If you want to lock some stuff for everyone, simply leave the auth-constraint element empty, like this:

1
2
3
4
5
6
7
8
    <security-constraint>
        <web-resource-collection>
            <web-resource-name>admin-area</web-resource-name>
            <url-pattern>/admin/</url-pattern>
        </web-resource-collection>
        <auth-constraint>
        </auth-constraint>
    </security-constraint>

If you’ve followed these instructions and the one on the blog-post Securing a Web Application on Glassfish using JAAS, you should now be able to authenticate different users with different roles in your app using the File-Realm.

In the next articles of the series, we will look how to create an own realm, how to replace the form-based login with a JSF-Based one and how to work with roles in your JSF-Pages.

References:

top