Lesson 1: Authenticating Users in a Legacy Spring Web Application
π― Lesson Objectives
By the end of this lesson, you will be able to:
β Understand Our current custom authentication flow
β Identify how user login, logout, and session management are handled
β
Recognize the role of AuthenticationFilter
and UserAdminPrincipal
β Appreciate the importance of login form validation
β Prepare for modernizing authentication with Spring Security
1οΈβ£ Current Authentication Architecture
Our current application uses custom authentication logic to protect resources and manage user sessions. Letβs break it down.
π¦ 1.1 Bootstrap Configuration
com.nicordesigns.site.config.Bootstrap
configures our servlet contexts and filters, including:
-
Authentication Filter: Ensures protected URLs (like
/registration
,/chat
,/session
) are accessible only by authenticated users. -
Logging Filter: Captures request/response logs.
β Code Snippet:
FilterRegistration.Dynamic authenticationFilter = container.addFilter("authenticationFilter", new AuthenticationFilter());
authenticationFilter.addMappingForUrlPatterns(null, false,
"/registration", "/registration/*", "/chat", "/chat/*", "/session", "/session/*");
π‘οΈ 1.2 Authentication Filter
com.nicordesigns.site.filters.AuthenticationFilter
is a servlet filter that:
β
Checks if the session contains a valid Principal
β
Redirects unauthenticated users to the login page (/login
)
β Wraps the request to expose the authenticated principal
β Code Snippet:
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpSession session = ((HttpServletRequest) request).getSession(false);
final Principal principal = UserAdminPrincipal.getPrincipal(session);
if (principal == null) {
((HttpServletResponse) response).sendRedirect(((HttpServletRequest) request).getContextPath() + "/login");
} else {
chain.doFilter(new HttpServletRequestWrapper((HttpServletRequest) request) {
@Override
public Principal getUserPrincipal() {
return principal;
}
}, response);
}
}
π€ 1.3 UserAdminPrincipal
com.nicordesigns.site.UserAdminPrincipal
manages the user identity:
β
Implements Principal
β Stores username
β
Provides static helpers to store/retrieve from HttpSession
β Code Snippet:
public static Principal getPrincipal(HttpSession session) {
return session == null ? null : (Principal) session.getAttribute("com.nicordesigns.user.principal");
}
public static void setPrincipal(HttpSession session, Principal principal) {
session.setAttribute("com.nicordesigns.user.principal", principal);
}
π 1.4 Login Form (JSP)
Our login.jsp
uses Spring tags for:
β Username and password input
β Field-level and general error messages
β Validation error display
β Example Snippet:
<form:form method="post" modelAttribute="loginForm">
<form:label path="username">Username</form:label><br/>
<form:input path="username" /><br/>
<form:errors path="username" cssClass="errors" />
<form:label path="password">Password</form:label><br/>
<form:password path="password" /><br/>
<form:errors path="password" cssClass="errors" /><br/>
<input type="submit" value="Login" />
</form:form>
βοΈ 1.5 AuthenticationController
The AuthenticationController
(com.nicordesigns.site.AuthenticationController
) manages:
β Login
β Logout
β Login form validation
β Session creation & management
β Key Features:
-
GET
/login
:- Shows login form
- Redirects if already logged in
-
POST
/login
:- Validates form fields
- Uses
AuthenticationService
to authenticate - Stores principal in session and regenerates session ID
- Redirects to
/registration/list
on success - Displays errors on failure
-
GET
/logout
:- Invalidates session
- Redirects to
/login
β Code Snippet:
@PostMapping(value = "login")
public ModelAndView login(@ModelAttribute("loginForm") @Valid LoginForm form,
Errors errors,
Map<String, Object> model,
HttpSession session,
HttpServletRequest request) {
log.info("login POST");
if (UserAdminPrincipal.getPrincipal(session) != null)
return getRegistrationRedirect();
if (errors.hasErrors()) {
form.setPassword(null);
return new ModelAndView("login");
}
Principal principal;
try {
principal = authenticationService.authenticate(form.getUsername(), form.getPassword());
} catch (ConstraintViolationException e) {
form.setPassword(null);
model.put("validationErrors", e.getConstraintViolations());
return new ModelAndView("login");
}
if (principal == null) {
form.setPassword(null);
model.put("loginFailed", true);
return new ModelAndView("login");
}
UserAdminPrincipal.setPrincipal(session, principal);
request.changeSessionId();
return getRegistrationRedirect();
}
π Current Flow Summary
β Login:
- Authenticates via
AuthenticationService
. - Stores user in session (
UserAdminPrincipal
). - Session ID changed to protect against fixation attacks.
β Session Validation:
AuthenticationFilter
ensures only logged-in users can access protected resources.
β Logout:
- Invalidates session and redirects to login page.
π Next Steps
Now that we have fully documented our existing login and authentication approach, weβre ready to:
β Identify gaps in security (e.g., CSRF protection, concurrent sessions)
β
Integrate Spring Security gradually, starting with basic SecurityFilterChain
to standardize authentication
β
Migrate existing AuthenticationController
logic to Spring Securityβs form login flow