4

I would like to implement a simple authentication in an JSF/Primefaces application. I have tried lots of different things, e.g. Dialog - Login Demo makes a simple test on a dialog, but it does not login a user or?

I also have taken a look at Java Security, like:

<security-constraint>
    <web-resource-collection>
        <web-resource-name>Protected Area</web-resource-name>
        <url-pattern>/protected/*</url-pattern>
        <http-method>PUT</http-method>
        <http-method>DELETE</http-method>
        <http-method>GET</http-method>
        <http-method>POST</http-method>
    </web-resource-collection>
    <auth-constraint>
        <role-name>REGISTERED_USER</role-name>
    </auth-constraint>
</security-constraint>

With this everything under /protected is protected, but as far as i understand i need to define a realm in the server for authentication. I do not want to specify this in the server but just have a simple lookup in the database for it.

Is there a way to authenticate a user without defining something in the application server? Or anonther simple solution to authenticate and protect different pages?

Sarz
  • 1,970
  • 4
  • 23
  • 43
Mike Petersen
  • 177
  • 2
  • 7

2 Answers2

7

Is there a way to authenticate a user without defining something in the application server?

This is a long and very thorny story. It often comes up as one the main points of criticism against Java EE.

The core of the story is that traditionally Java EE applications are supposed to be deployed with "unresolved dependencies". Those dependencies have to be satisfied at the application server, typically by someone who is not a developer, often by using some kind of GUI or console.

Security configuration is one of those unresolved dependencies.

If the security configuration is done at the application server, this is by definition always not portable, e.g. it has to be done in an application server specific way. It completely rules out using application domain models (e.g. a JPA entity User) for this authentication.

Some servers (e.g. JBoss AS) allow configuring their proprietary security mechanisms from within the application, and additionally allow for 'custom login modules' (the term is different for pretty much every server) to be loaded from the application as well. With some small hacks, this will allow the usage of application domain models and the same data source that the application itself uses for authentication.

Finally, there's a relatively unknown portable way to do authentication from within an application. This is done via the JASPIC SPI, also known as JASPI or JSR 196. Basically, this JASPIC seems to be what you are looking for.

Unfortunately, JASPIC is not perfect and even though it's a technology from Java EE 6 and we're almost at Java EE 7, at the moment support for JASPIC in various application servers is still sketchy. On top of that, even though JASPIC is standardized, application server vendors still somehow require proprietary configuration to actually make it work.

I wrote an article about JASPIC that explains the current problems in more detail: Implementing container authentication in Java EE with JASPIC

Arjan Tijms
  • 37,782
  • 12
  • 108
  • 140
  • Sounds a bit strange. If i have the authentication in the application server it is not portable anymore. If i use another application server i have to migrate the whole userbase over or reimplement it. I will take a look at the JASPIC may this helps me, Thanks. – Mike Petersen Dec 30 '12 at 15:25
  • @MikePetersen Indeed, but that's the idea of the traditional approach. It's app server centric vs application centric. The idea is that you run a multitude of apps on a single app server, and they all use the same authentication. Therefor it's setup at the app server. Of course, if all you ever do is running a single app that has its own authentication it doesn't make sense. So, it depends on the situation. One approach is not better that the other, there are just different use cases. – Arjan Tijms Dec 30 '12 at 17:28
  • Xou are right if you have more apps that use the same user base it makes sense. I thought that different apps with different authentications is more common for web applications. – Mike Petersen Dec 30 '12 at 21:53
0

I have found a for me suitable and easy solution by simply using Web Filters. I have added a filter to web.xml like

<!-- Authentication Filter -->
<filter>
    <filter-name>AuthenticationFilter</filter-name>
    <filter-class>org.example.filters.AuthenticationFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>AuthenticationFilter</filter-name>
    <url-pattern>/protected/*</url-pattern>
</filter-mapping>

The filter looks something like this

@WebFilter(filterName="AuthenticationFilter")
public class AuthenticationFilter implements Filter {

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        Cookie[] cookies = ((HttpServletRequest)request).getCookies();

        // Try to find a valid session cookie
        if (cookies != null) {
            String sessionId = null;
            for (Cookie cookie : cookies) {
                if ("sessionId".equals(cookie.getName())) {
                        sessionId = cookie.getValue();
                }
            }

            // Check if we have a valid session
            UserSession session = Backend.getInstance().getSessionGateway().getBySessionId(sessionId);

            if (session != null) {
                chain.doFilter(request, response);
                return;
            } else if (sessionId != null) {
                // Remove the cookie
                Cookie cookie = new Cookie("sessionId", null);
                cookie.setMaxAge(-1);
                ((HttpServletResponse)response).addCookie(cookie);
            }
        }


//      Problem due to relative path!!
//      ((HttpServletResponse)response).sendRedirect("../login.xhtml");
        RequestDispatcher rd = request.getRequestDispatcher("/login.xhtml");
        rd.forward(request, response);
    }
}

So i had just to implement a Bean that authenticates and sets the session cookie. I will add the user agent to have additional security but it basically works.

The only problem i have that i can not do a redirect, cause it is not using context path but just redirects to /index.xhtml instead of /my_app_context/index.xhtml

Mike Petersen
  • 177
  • 2
  • 7