Authentication in JSF2 with JAAS: Part 2 – Authenticating a client/user

25 Feb
2010

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:

16 Responses to Authentication in JSF2 with JAAS: Part 2 – Authenticating a client/user

Avatar

Fritz Solms

April 7th, 2010 at 08:00

A nice foundation article. When is part 3 coming out?

Avatar

Andraz

April 13th, 2010 at 19:19

When can we expect to see part 3, 4, … ?

Avatar

Dominik Dorn

April 15th, 2010 at 22:13

I’m currently quite busy with other stuff and I’m also currently doing all authentication with a JDBCRealm based configuration.

I will put a part 3 fro JDBCRealm based config on my todo list, but will probably not have time for it until beginning of may.

Avatar

ParchdoXa

April 15th, 2010 at 23:31

Your blog keeps getting better and better! Your older articles are not as good as newer ones you have a lot more creativity and originality now. Keep it up!
And according to this article, I totally agree with your opinion, but only this time! 🙂

Avatar

apcuk

June 3rd, 2010 at 15:43

Hi, great posts, but I’m dying for that 3rd part 🙂

Avatar

Vítor Souza

June 15th, 2010 at 13:18

Hi, nice post! I’m very interested in the subject!

Having tried Seam and then moving to Java EE 6 when it was released, I really missed the ability to login programmatically. Other than authenticating the user in the Realm, I also want to register some stuff in a Session-scoped Stateful EJB that stores session information for the current user.

What I ended up doing was having this EJB component lazily initialize the current user looking if the context already has an authenticated principal:

// Declared as an attribute of the EJB:
@Resource private SessionContext sessionContext;

// Part of the method that retrieves the current user’s information from the database:

private void checkCredentials() {
Principal principal = sessionContext.getCallerPrincipal();
if (principal != null) {
String username = principal.getName();
if (!”ANONYMOUS”.equals(username)) {
// Retrieve from the database…
}
}
}

But I don’t like that solution. I looked into programmatic login but it seems to be outside the standard and vendor-specific.

Could you comment about this on your next posts? I’m looking forward to see how you’re going to implement the FORM authentication with JSF…

Avatar

Dominik Dorn

June 16th, 2010 at 15:30

@Vitor:

Currently I’m always injecting the HttpServletRequest into a CDI bean, calling request.login(username, password) there. if that does not throw an exception, I store additional stuff in the (Http)session.

But sure, will blog about that too.

Avatar

Attila

June 21st, 2010 at 00:34

Hi!
Nice tutorial, I’m also waiting for part 3 🙂

Avatar

Vítor Souza

June 21st, 2010 at 16:13

I tried defining an HttpServletRequest property in my EJB with the @Resource annotation but it didn’t work. I didn’t try other CDI annotations (e.g. @Inject). I ended up getting it from the context:

HttpServletRequest request = (HttpServletRequest)FacesContext.getCurrentInstance().getExternalContext().getRequest();

I also added catches for NullPointerException and ClassCastException to show user-friendly messages in case something goes bad…

Anyways, I’ll wait for your next post to see how you do it.\

Thanks again!
Vítor

Avatar

Dominik Dorn

June 24th, 2010 at 12:59

@Vitor: Thats essentially what Seam Faces, which is led by my friend Lincoln Baxter, III., does: it provides a Producer-Method for certain things like FacesContext, HttpServletRequest, etc.

Take a look at http://seamframework.org/Seam3/FacesModule

After including it into your webapp, you could simply use
@Inject HttpServletRequest request;
in your beans.

Avatar

Wikisky

July 19th, 2010 at 18:54

Great post. Is there any hope for next part?
Thanks

Avatar

Vinnie

September 19th, 2010 at 07:45

Great post. I’m developing a JSF app and looking for JSF security example.
I’m waiting for your next part 3. Please share your best experience with JSF security. Thank you.

Avatar

SundjerBob

September 24th, 2010 at 15:22

Hi,
For all of you who haven’t lost 3 hours on this yet,
instead of

action=”/j_security_check”

in form tag,
goes

action=”j_security_check”

thanks for the tutorial

Avatar

Dominik Dorn

September 24th, 2010 at 21:41

Thanks SundjerBob for the comment.
Actually it has to be #{request.contextPath}/j_security_check as it would otherwise not work with rewritten urls. If adapted the post to reflect this change.

Avatar

Paulo

June 7th, 2011 at 16:41

Thanks for this tutorial but when i create a form with action=”j_security_logout”, the user is not really logout. Have you any idea about this problem ?

Avatar

Dominik Dorn

June 7th, 2011 at 16:46

the action has to be relative to the webapp-context root, e.g. action=”#{request.contextPath}/j_security_logout”

Comment Form

top