Java EE authentication: how to log in a login event?

Given the authentication mechanism of the FORM type defined for the Java web application, how do you record the event that was executed to log in before redirecting to the requested resource? Is there any listener where I can put my code to execute when the user logs in?

It seems to me that defining a filter is not the best solution, since the filter is associated with the resource and will be called even if the user has already authenticated and requests the resource. I am wondering if some class / method only starts when registering.

+6
source share
2 answers

There is no such event in Java EE. Yet. Under JSR375 , container-managed security will be completely redesigned as it is currently scattered across different container implementations and is not compatible with containers. This is stated in the presentation of the Java EE 8 Security API .

There is already a reference implementation of the Soteria security API , developed by Arjan Tijms among my other colleagues. With the new security API, CDI will be used to trigger authentication events that you can simply @Observes . Discussion of this specification took place in this mailing list chain . This is not yet implemented in Soteria.

Until then, provided that FORM based authentication, in which the user-user will be stored internally in the session, your best choice is checked manually in servlet filters, if the request contains a user principle, while your representation of the registered user is a user absent in an HTTP session.

 @Override public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) { HttpServletRequest request = (HttpServletRequest) req; String username = request.getRemoteUser(); if (username != null && request.getSession().getAttribute("user") == null) { // First-time login. You can do your thing here. User user = yourUserService.find(username); request.getSession().setAttribute("user", user); } chain.doFilter(req, res); } 

Please note that registering a filter on /j_security_check not guaranteed, since a decent container will process it inside before the first filters are deleted, for obvious security reasons (filters provided by the user can poorly manipulate the request, either by accident or deliberately) .

If you, however, use a Java EE server, use an Undertow servletcontainer, such as WildFly , then there is a cleaner way to connect to your internal notification events and then fire custom CDI events. This is featured on this Arjan Tijms blog . As the blog post shows, you can end up creating a CDI bean as follows:

 @SessionScoped public class SessionAuthListener implements Serializable { private static final long serialVersionUID = 1L; public void onAuthenticated(@Observes AuthenticatedEvent event) { String username = event.getUserPrincipal().getName(); // Do something with name, eg audit, // load User instance into session, etc } public void onLoggedOut(@Observes LoggedOutEvent event) { // take some action, eg audit, null out User, etc } } 
+7
source

You can use the servlet filter in the j_security_check URI. This filter will not be called on every request, but only on the login request.

Check out the next page — Designing Servlet Filters to Process Form Login — This works in WebSphere App Server and in the WebSphere Liberty profile.

The presence of such a filter:

 @WebFilter("/j_security_check") public class LoginFilter implements Filter { ... public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { System.out.println("Filter called 1: " +((HttpServletRequest)request).getUserPrincipal()); chain.doFilter(request, response); System.out.println("Filter called 2: " + ((HttpServletRequest)request).getUserPrincipal()); } 

gives the following result:

 // on incorrect login Filter called 1: null [AUDIT ] CWWKS1100A: Authentication did not succeed for user ID user1. An invalid user ID or password was specified. Filter called 2: null // on correct login Filter called 1: null Filter called 2: WSPrincipal:user1 

UPDATE

Another possible way to do this is to use your servlet to login, change the action on the login page of this servlet, and use the request.login() method. This is the servlet API, so it should work even in Wildfly, and you have full control over the login. You just need to figure out how wildfly passes the originally requested resource URL (WebSphere does this through a cookie).

Servlet Pseudo Code:

 public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String user = request.getParameter("j_username"); String password = request.getParameter("j_password"); try { request.login(user, password); // redirect to requested resource } catch (Exception e) { // login failed - redirect to error login page } 
0
source

All Articles