Skip to content

Upgrade to Spring Boot 3.5.8 and Enable Spring Security #1

@ebouchut

Description

@ebouchut

Upgrade to Spring Boot 3.5.8 and Enable Spring Security

Overview

This issue tracks the upgrade from Spring Boot 3.0.4 to 3.5.8 and the proper activation of Spring Security in our application.

Why Upgrade?

1. Security and Support

  • Spring Boot 3.0.4 was released in February 2023 and is past its 13-month community support window
  • No longer receiving security updates or bug fixes
  • Spring Boot 3.5.8 (released November 2025) is actively maintained with:
    • 57 bug fixes and security patches
    • Dependency upgrades
    • Active community support through 2026

2. New Features in 3.5.x

  • WebClient Configuration Properties: Global timeout and redirect configuration
  • Client-Side SSL Support: Enhanced security for service connections
  • @ServletRegistration/@FilterRegistration: Modern annotation-based servlet/filter registration
  • Apache Pulsar 4.0.x: Upgraded to new LTS release
  • Performance Improvements: Various optimizations and dependency updates

3. Future-Proofing

  • Easier migration path to future Spring Boot versions
  • Access to latest Spring Framework 6.x features
  • Better alignment with Spring ecosystem

Breaking Changes to Address

1. Deprecated Code Removal

Classes, methods, and properties deprecated in Spring Boot 3.3 have been removed in 3.5.

Action Required:

  • ✅ Our codebase is minimal and doesn't use deprecated APIs
  • Review any future code additions for deprecated usage

2. Configuration Property Validation

.enabled properties now require strict true/false values.

Action Required:

  • ✅ Review src/main/resources/application.yaml
  • ✅ Verify test configuration in src/test/resources/application-test.yaml

3. Heapdump Actuator Endpoint Security

Defaults to access=NONE for security.

Action Required:

  • ✅ Not using Actuator endpoints currently - no action needed
  • If added in future: explicitly configure heapdump access

4. WebClient Behavior Changes

Redirects now enabled by default to align with blocking clients.

Action Required:

  • ✅ Not using WebClient currently - no action needed
  • Future WebClient usage will follow redirects automatically

5. spring-boot-parent Module Removed

The spring-boot-parent module is no longer published.

Action Required:

  • ✅ We use spring-boot-starter-parent - no change needed

Pre-Upgrade Checklist

  • Verify Java 17 is in use (required baseline)
  • Review dependencies for compatibility
  • Ensure tests pass on current version (3.0.4)
  • Review configuration files for deprecated properties
  • Backup current working state
  • Update pom.xml parent version
  • Run ./mvnw clean test to verify compatibility
  • Update CLAUDE.md and README.md with new version info

Upgrade Steps

Step 1: Update pom.xml

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>3.5.8</version>
    <relativePath/>
</parent>

Step 2: Clean Build and Test

./mvnw clean
./mvnw test

Step 3: Verify Application Startup

export FLASHCARD_DB_PASSWORD=your_password
./mvnw spring-boot:run

Step 4: Review Logs

Check for deprecation warnings or migration hints in startup logs.

Spring Security Activation Plan

Spring Security is already included as a dependency but not properly configured.

Current State

File: src/main/java/com/ericbouchut/java/springboot/flashcard/config/SecurityConfiguratio.java

@Configuration
public class SecurityConfiguratio {  // ⚠️ Typo in class name
    // TODO: Configure public URLs
    // TODO: Configure protected URLs
}

Issues:

  1. Class name typo: SecurityConfiguratioSecurityConfiguration
  2. No SecurityFilterChain bean defined
  3. No UserDetailsService implementation (commented out in AuthenticationService)
  4. No PasswordEncoder bean

Spring Security 6 Requirements

Spring Boot 3.5.8 uses Spring Security 6, which has significant API changes:

❌ Deprecated/Removed APIs (DO NOT USE)

  • WebSecurityConfigurerAdapter - Removed in Spring Security 6
  • .authorizeRequests() - Deprecated, use .authorizeHttpRequests()
  • .antMatchers() / .mvcMatchers() / .regexMatchers() - Removed
  • Inheritance-based configuration

✅ Modern Spring Security 6 APIs (USE THESE)

  • SecurityFilterChain bean-based configuration
  • .authorizeHttpRequests() with lambda DSL
  • .requestMatchers() for path-based authorization
  • Component-based configuration with @Bean methods

Implementation Checklist

Phase 1: Basic Security Setup

  • Rename SecurityConfiguratio.java to SecurityConfiguration.java
  • Create SecurityFilterChain bean with basic authentication
  • Create PasswordEncoder bean (BCryptPasswordEncoder)
  • Configure public endpoints (login, register, static resources)
  • Configure protected endpoints (require authentication)
  • Test default login behavior

Example SecurityFilterChain:

@Configuration
@EnableWebSecurity
public class SecurityConfiguration {

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
            .authorizeHttpRequests(authorize -> authorize
                .requestMatchers("/", "/public/**", "/login", "/register", "/css/**", "/js/**").permitAll()
                .requestMatchers("/admin/**").hasRole("ADMIN")
                .anyRequest().authenticated()
            )
            .formLogin(form -> form
                .loginPage("/login")
                .defaultSuccessUrl("/home", true)
                .permitAll()
            )
            .logout(logout -> logout
                .logoutUrl("/logout")
                .logoutSuccessUrl("/login?logout")
                .permitAll()
            );

        return http.build();
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
}

Phase 2: UserDetailsService Implementation

  • Create UserRepository interface extending JpaRepository
  • Add findByEmail(String email) method to repository
  • Uncomment and complete AuthenticationService implementation
  • Implement loadUserByUsername() method
  • Add proper exception handling

File: src/main/java/com/ericbouchut/java/springboot/flashcard/repository/UserRepository.java

package com.ericbouchut.java.springboot.flashcard.repository;

import com.ericbouchut.java.springboot.flashcard.model.User;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

import java.util.Optional;

@Repository
public interface UserRepository extends JpaRepository<User, Integer> {
    Optional<User> findByEmail(String email);
}

File: src/main/java/com/ericbouchut/java/springboot/flashcard/service/AuthenticationService.java

@Service
public class AuthenticationService implements UserDetailsService {
    private final UserRepository userRepository;

    public AuthenticationService(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    @Override
    public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException {
        User user = userRepository.findByEmail(email)
            .orElseThrow(() -> new UsernameNotFoundException("User not found with email: " + email));

        return org.springframework.security.core.userdetails.User
            .withUsername(user.getEmail())
            .password(user.getPassword())
            .roles("USER") // TODO: Add role management
            .build();
    }
}

Phase 3: User Entity Updates

  • Fix password validation in User.java
  • Ensure passwords are BCrypt-encoded before saving
  • Add role/authority support to User entity

Current Issue in src/main/java/com/ericbouchut/java/springboot/flashcard/model/User.java:40-42:

@NotBlank        // Required
@Min(value = 6L) // ⚠️ WRONG: Validates numeric values, not string length
private String password;

Fix:

@NotBlank(message = "Password is required")
@Size(min = 6, message = "Password must be at least 6 characters")
private String password;

Phase 4: MVC Configuration

  • Complete MvcConfig.java with view controllers
  • Configure login form path and view
  • Add view mappings for authentication pages

File: src/main/java/com/ericbouchut/java/springboot/flashcard/config/MvcConfig.java

@Configuration
public class MvcConfig implements WebMvcConfigurer {

    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        registry.addViewController("/login").setViewName("login");
        registry.addViewController("/").setViewName("home");
    }
}

Phase 5: CSRF Configuration

  • Decide CSRF strategy (enabled for web forms, disabled for REST APIs)
  • Configure CSRF token handling in Thymeleaf templates
  • Add CSRF exemptions for stateless API endpoints if needed

Considerations:

// For traditional web app (forms): Keep CSRF enabled (default)
http.csrf(Customizer.withDefaults());

// For REST APIs: Disable CSRF for API endpoints only
http.csrf(csrf -> csrf
    .ignoringRequestMatchers("/api/**")
);

// For fully stateless REST API: Disable completely
http.csrf(csrf -> csrf.disable());

Phase 6: Testing

  • Create security test configuration
  • Add @WithMockUser tests for protected endpoints
  • Test login/logout flows
  • Test unauthorized access handling
  • Verify CSRF protection works correctly

File: src/test/resources/application-test.yaml - Add:

spring:
  security:
    user:
      name: test
      password: test

Test Example:

@SpringBootTest
@AutoConfigureMockMvc
@ActiveProfiles("test")
class SecurityConfigurationTest {

    @Autowired
    private MockMvc mockMvc;

    @Test
    void publicEndpointShouldBeAccessibleWithoutAuthentication() throws Exception {
        mockMvc.perform(get("/public/test"))
            .andExpect(status().isOk());
    }

    @Test
    void protectedEndpointShouldRequireAuthentication() throws Exception {
        mockMvc.perform(get("/protected"))
            .andExpect(status().is3xxRedirection())
            .andExpect(redirectedUrlPattern("**/login"));
    }

    @Test
    @WithMockUser(username = "test@example.com", roles = "USER")
    void protectedEndpointShouldBeAccessibleWhenAuthenticated() throws Exception {
        mockMvc.perform(get("/protected"))
            .andExpect(status().isOk());
    }
}

Important Security Considerations

1. Password Encoding

CRITICAL: Never store passwords in plain text!

// During user registration/password change:
String encodedPassword = passwordEncoder.encode(rawPassword);
user.setPassword(encodedPassword);
userRepository.save(user);

2. Default Security Behavior

When Spring Security is active, all endpoints are protected by default unless explicitly permitted.

3. CSRF Protection

  • Enabled by default for state-changing operations (POST, PUT, DELETE)
  • Must include CSRF token in forms
  • Thymeleaf provides automatic CSRF token injection

4. Session Management

Consider configuring session creation policy:

http.sessionManagement(session -> session
    .sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)
    .maximumSessions(1)
    .maxSessionsPreventsLogin(true)
);

Testing Strategy

Pre-Security Activation Tests

  1. Run all existing tests: ./mvnw test
  2. Verify application starts: ./mvnw spring-boot:run
  3. Confirm database connectivity

Post-Security Activation Tests

  1. Verify login page is accessible
  2. Test valid login credentials
  3. Test invalid login credentials
  4. Test logout functionality
  5. Test protected endpoint access without authentication
  6. Test protected endpoint access with authentication
  7. Verify CSRF protection on forms
  8. Test password encoding/validation

Documentation Updates

  • Update README.md with Spring Boot version
  • Update CLAUDE.md with security configuration patterns
  • Document authentication flow
  • Add security testing guidelines
  • Update prerequisites section

Migration Resources

Timeline Proposal

Phase 1: Spring Boot Upgrade (Week 1)

  • Update pom.xml
  • Run tests
  • Verify compatibility
  • Update documentation

Phase 2: Security Foundation (Week 2)

  • Fix SecurityConfiguration class
  • Implement SecurityFilterChain
  • Create PasswordEncoder bean
  • Test basic security

Phase 3: Authentication Implementation (Week 3)

  • Create UserRepository
  • Complete AuthenticationService
  • Fix User entity validation
  • Test user authentication

Phase 4: MVC & Views (Week 4)

  • Complete MvcConfig
  • Create login/logout views
  • Configure CSRF handling
  • Integration testing

Phase 5: Final Testing & Documentation (Week 5)

  • Comprehensive security testing
  • Update all documentation
  • Code review
  • Deployment preparation

Success Criteria

  • Application runs on Spring Boot 3.5.8
  • All existing tests pass
  • Security configuration is complete and functional
  • User authentication works correctly
  • Protected endpoints require authentication
  • Public endpoints remain accessible
  • CSRF protection is properly configured
  • Passwords are properly encoded
  • Documentation is up-to-date
  • Security tests have adequate coverage

Risks and Mitigation

Risk Likelihood Impact Mitigation
Breaking changes in dependencies Low Medium Thorough testing after upgrade
Security misconfiguration Medium High Follow Spring Security best practices, peer review
Test failures after upgrade Low Low Minimal codebase, fix as needed
Authentication issues Medium High Incremental implementation with testing
CSRF token handling in views Medium Medium Use Thymeleaf CSRF support

Related Issues

  • TODO: Add issue for implementing user registration
  • TODO: Add issue for implementing password reset
  • TODO: Add issue for role-based authorization
  • TODO: Add issue for implementing "Remember Me" functionality

Questions / Discussion

  1. Should we implement role-based authorization immediately or in a follow-up issue?
  2. Do we need OAuth2/Social login support?
  3. Should we add Spring Security method-level security (@PreAuthorize, @Secured)?
  4. Do we need API endpoints that require different security configuration?

Labels: enhancement, security, upgrade, breaking-change
Priority: High
Assignee: TBD
Milestone: v0.1.0

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requestsecuritySecurity-related issues and improvementsupgradeVersion upgrades and dependency updates

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions