Migrate to spring boot 4#3805
Conversation
|
thanks for this PR, we need to solve OpenSAML first and therefore started with: #3811 |
This version is support BC fips. Higher versions pull directly classes from non fips package. At least a version that could work together with spring security 7.x and then boot 4.x
|
@gdgenchev ok, with spring update you need opensaml5 and therefore rebase this and also pull changes from #3840 for testing. with this your SAML erros should disappear |
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
5e94f36 to
f142b62
Compare
43ae15f to
2e4a063
Compare
…rate-to-spring-boot-4 # Conflicts: # server/src/main/java/org/cloudfoundry/identity/uaa/provider/saml/Saml2BearerGrantAuthenticationConverter.java # server/src/main/java/org/cloudfoundry/identity/uaa/provider/saml/SamlAuthenticationFilterConfig.java
In Spring 6.2.x handleError(ClientHttpResponse response) was deprecated and later removed in Spring 7.x in favor of handleError(URI url, HttpMethod method, ClientHttpResponse response)
Spring Boot 4 moved DependsOnDatabaseInitialization to a separate spring-boot-sql module. Added this dependency to the server module where it's needed. Related to Spring Boot 4 migration.
Spring Security 7 moved vote classes (AuthenticatedVoter, RoleVoter, UnanimousBased) to a separate spring-security-access module that is not automatically included. Added explicit dependency. Related to Spring Boot 4 migration.
Spring Security 7 removed the Base64 class from the spring-security-crypto.codec package. Replaced with java.util.Base64 in all files that used org.springframework.security.crypto.codec.Base64. Related to Spring Boot 4 migration.
Spring Boot 4 moved autoconfigure classes to technology-specific modules: - org.springframework.boot.autoconfigure.jdbc → org.springframework.boot.jdbc.autoconfigure - org.springframework.boot.autoconfigure.transaction → org.springframework.boot.transaction.autoconfigure Updated DatabaseConfiguration imports. Related to Spring Boot 4 migration.
Spring Boot 4 reorganized autoconfigure packages. - Removed unused WebMvcAutoConfiguration import from WebConfig - Updated test annotation to use new autoconfigure package locations Related to Spring Boot 4 migration.
Replace deprecated HttpComponentsClientHttpRequestFactory.setConnectTimeout() with ConnectionConfig.setConnectTimeout() on PoolingHttpClientConnectionManager. The connection timeout is now configured at the connection manager level using the recommended ConnectionConfig.Builder API.
Spring Framework 7 replaced HttpHeaders.containsKey() with containsHeader(). This updates all occurrences in OAuth2 token handling code and test utilities. Related to Spring Boot 4 migration.
…ng 7 Spring 7 removed MediaType.sortByQualityValue() and QUALITY_VALUE_COMPARATOR that were deprecated in Spring 6. Copy the sorting logic into a new MediaTypeComparators utility class to preserve content negotiation behavior that respects client quality value preferences from Accept headers. https://github.com/spring-projects/spring-framework/blob/9f431e2eac1b6d8d5ca385d0cc367bac94dd37e7/spring-web/src/main/java/org/springframework/http/MediaType.java#L927-L965
- Rename MediaTypeComparators to MediaTypeUtils for better semantics - Add sortByQualityValue() utility method to handle immutable lists - Fix usages to create mutable copies before sorting - Remove unnecessary if-else in ConvertingExceptionView - Add comprehensive unit tests including parameterized tests
In Spring Boot 4, LDAP and Session support became optional starters: - spring-boot-starter-ldap - spring-boot-starter-session-* Since these starters are not included as dependencies, their AutoConfiguration classes don't exist on the classpath and don't need to be excluded. Removed exclusions: - LdapAutoConfiguration - SessionAutoConfiguration **Cannot be done in isolation** - Boot 4 only change.
Spring Security 7's DaoAuthenticationProvider rejects empty passwords. Handle empty credentials by manually checking password encoding instead of calling super.additionalAuthenticationChecks().
Spring Security 7 changed LoginUrlAuthenticationEntryPoint to generate relative URLs by default instead of absolute URLs.
Spring Framework 7 changes: 1. LoginUrlAuthenticationEntryPoint now generates relative URLs by default instead of absolute URLs. Updated CSRF redirect assertions from 'http://localhost/login' to '/login'. 2. MockHttpServletResponse.getCookie() no longer automatically parses Set-Cookie headers added via addHeader(). Updated cookie expiry test to check Set-Cookie header directly, which is more accurate since that's what browsers receive.
Spring Security 7's RelyingPartyRegistration.mutate() is called by UaaRelyingPartyRegistrationResolver. Mock the builder chain to prevent NPE.
Replace providedRuntime(spring-boot-starter-tomcat) with providedRuntime(spring-boot-starter-tomcat-runtime) per the Spring Boot 4 migration guide for external Tomcat WAR deployment. In Spring Boot 4, spring-boot-starter-tomcat transitively pulls in spring-boot-starter which includes spring-boot, spring-context etc., causing those to land in WEB-INF/lib-provided and be missing at runtime on external Tomcat. The new spring-boot-starter-tomcat-runtime artifact contains only the Tomcat embed jars that the container actually provides. Also remove the now-redundant providedCompile(tomcatEmbed) — originally added to provide javax.servlet.* at compile time, but tomcat-embed-core is already available transitively via spring-boot-starter-web.
Spring Boot BOM version resolution requires explicit version.
# Conflicts: # dependencies.gradle
Spring Boot 4 defaults to Jackson 3 (spring-boot-jackson) via spring-boot-starter-web. This breaks custom Jackson 2 serializers (e.g. OAuth2ExceptionJackson2Serializer) and spring.jackson.* property binding which uses tools.jackson enums instead of com.fasterxml.jackson enums. Globally exclude spring-boot-jackson and add spring-boot-jackson2 (the Jackson 2 compatibility layer) per the Spring Boot 4 migration guidance for projects staying on Jackson 2.
In Spring Boot 4, Flyway auto-configuration was extracted from spring-boot-autoconfigure into the separate spring-boot-flyway module. Without it, FlywayDatabaseInitializerDetector is not registered, making @DependsOnDatabaseInitialization a no-op and causing beans to query the database before Flyway migrations have run.
…-config SecurityAutoConfiguration previously provided a DefaultAuthenticationEventPublisher bean via spring-boot-autoconfigure. In Spring Boot 4 it moved to the separate spring-boot-security module which is not on the classpath.
Spring Security 7 enforces that patterns passed to requestMatchers() must start with a /. The pattern "oauth/clients/meta" was missing the leading slash.
…tdocs spring-restdocs-core:4.0.0 depends on tools.jackson.core:jackson-databind:3.0.2. With Jackson 3 on the classpath, Spring Framework 7's DefaultHttpMessageConverters selects JacksonJsonHttpMessageConverter (Jackson 3) over MappingJackson2HttpMessageConverter (Jackson 2). Jackson 3 ignores Jackson 2's @JsonSerialize annotations, causing OAuth2AccessToken responses to use bean-property serialization ("value", "tokenType") instead of the custom serializer output ("access_token", "token_type"). This fixes ~1727 of the ~1783 test failures in the uaa module.
Spring Security 7's LoginUrlAuthenticationEntryPoint.favorRelativeUris defaults to true, returning relative URLs (/login) instead of absolute URLs (http://localhost/login). Update all affected test assertions in login, invitation, password reset, and SCIM group endpoint tests.
Spring Security 7 treats anonymous requests as authenticated (with AnonymousAuthenticationToken) but unauthorized, returning 403 Forbidden instead of 401 Unauthorized when accessing protected API endpoints without a Bearer token.
…ng Security 7 Spring Security 7's HttpSessionRequestCache.matchesSavedRequest() now calls savedRequest.getRedirectUrl() without null check, and FrameworkServlet.service() calls Set.contains(request.getMethod()) which throws on null. Both NPE when the mock doesn't stub these methods.
Spring Security 7's DelegatingPasswordEncoder now extends
AbstractValidatingPasswordEncoder which rejects empty rawPassword
in matches(). Non-UAA users store "" encoded as "{noop}" — assert
the stored value directly instead of going through matches().
Spring Security 7's AbstractLdapAuthenticationProvider now adds a
FactorGrantedAuthority("FACTOR_PASSWORD") to every password-based
authentication. This is framework-internal MFA tracking, not a UAA
scope. Filter it from test assertions that verify UAA scope mapping.
2e4a063 to
51d132e
Compare
Run org.openrewrite.java.jackson.UpgradeJackson_2_3 via Moderne CLI. Covers 127 files with mechanical renames: - com.fasterxml.jackson.core → tools.jackson.core - com.fasterxml.jackson.databind → tools.jackson.databind - JsonSerializer → ValueSerializer - JsonDeserializer → ValueDeserializer - SerializerProvider → SerializationContext - IOException → JacksonException in catch blocks - writeObjectField → writeObjectProperty - textValue() → asString() Note: com.fasterxml.jackson.annotation imports are unchanged (jackson-annotations remains at com.fasterxml namespace in Jackson 3).
- Remove global exclusions for tools.jackson.core and tools.jackson (we now use Jackson 3 directly) - Remove spring-boot-jackson exclusion (Jackson 3 auto-config is wanted) - Switch jacksonDatabind to tools.jackson.core:jackson-databind - Switch jacksonDataformatYaml to tools.jackson.dataformat:jackson-dataformat-yaml - Remove spring-boot-jackson2 dependency from server and uaa modules
Jackson 3 changed several defaults from Jackson 2. Configure both JsonUtils and JacksonMapperCustomizer to restore Jackson 2 behavior: - DateTimeFeature.WRITE_DATES_AS_TIMESTAMPS: was true (Jackson 2), now false - SerializationFeature.FAIL_ON_EMPTY_BEANS: was true (Jackson 2), now false - DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES: was false (Jackson 2), now true - MapperFeature.SORT_PROPERTIES_ALPHABETICALLY: was false (Jackson 2), now true - ConstructorDetector: prevent Jackson 3 from preferring multi-param constructors when a no-arg constructor exists Also catch JacksonException in convertValue (Jackson 3 throws MismatchedInputException directly instead of wrapping in IllegalArgumentException).
The spring.jackson.serialization.write-dates-as-timestamps property is no longer valid in Jackson 3/Spring Boot 4. The date timestamp behavior is now configured directly in the ObjectMapper via DateTimeFeature.WRITE_DATES_AS_TIMESTAMPS in JacksonMapperCustomizer. Also remove the javadoc and @propertysource annotation since the property file no longer exists.
Manual corrections for Jackson 3 API changes that the OpenRewrite recipe either missed or got wrong: - getCurrentToken() → currentToken(), getCurrentName() → currentName() - writeObjectProperty() → writePOJOProperty() for writing POJO fields - SimpleType.construct() removed; use ctxt.constructType() instead - JsonUtils.readTree(parser) → parser.readValueAsTree() in deserializers - StreamReadException constructor changed: use (parser, message, cause) - UnrecognizedPropertyException: use .from(parser, ...) factory method - DatabindException: use .from(parser, message) factory method - Remove leftover IOException imports - Remove empty @JsonSerialize/@JsonDeserialize on ExpiringCode - Replace deprecated @JsonSerialize(include=) with @JsonInclude - Remove deprecated include= parameter from @JsonSerialize on ScimMeta
IdToken: Add @JsonCreator with explicit @JsonProperty on all constructor parameters. Jackson 3 reports conflicting property names when a field has @JsonProperty("cid") but the getter has @JsonProperty("client_id"). The explicit @JsonCreator annotation resolves the ambiguity. HeaderParameters: Remove @JsonCreator from the 3-param constructor. Jackson 3's ConstructorDetector was selecting it during convertValue() operations even when 'alg' was absent, causing "alg is required" errors. The no-arg constructor with field-level @JsonProperty handles deserialization correctly.
- Update exception class name assertions: com.fasterxml.jackson.core.JsonParseException → tools.jackson.core.exc.StreamReadException com.fasterxml.jackson.databind.exc.InvalidDefinitionException → tools.jackson.databind.exc.InvalidDefinitionException IllegalArgumentException → MismatchedInputException (convertValue) - JsonDateDeserializerTest: pass JsonParser instead of TokenStreamLocation - JsonDateSerializerTest: use JsonMapper.shared().createGenerator() instead of TokenStreamFactory (removed in Jackson 3) - JsonTranslation: enable WRITE_DATES_AS_TIMESTAMPS (no longer default) - OAuth2AccessTokenJackson2SerializerTests: DatabindException → IllegalArgumentException (thrown directly by serializer, not wrapped by Jackson 3) - SAML tests: use Jackson 2 ObjectMapper for Spring Security's Jackson2 modules (SecurityJackson2Modules requires Jackson 2 ObjectMapper)
|
Current Progress: I picked saml 5 update. I did spring boot 4 migration without open rewrite from scratch, incrementally, so that I can isolate changes that are compatible with current Spring Boot 3. All such have been proposed as PRs. Maybe we can also try with open rewrite after those are merged. I reached a point where all unit tests pass and 35 ITs failed. But apidoc pipeline failed with Jackson issues, as I tried keeping Jackson 2... As effort was too high to make it work with Jackson 2, I just decided to try to migrate the whole project to Jackson 3 and it seems it worked nicely. Unit tests still pass, apidoc passes, but we have 90 failing ITs and I see some stacktraces related to jackson. Will check. |
I have worked on researching the spring boot 4 migration of uaa.
Current State:
Conclusions:
Jackson:
spring-boot-jackson2. I was given a recipe that does the spring migration without Jackson and this is the one that I have used as a base. I was suggested to do Spring Boot 4 without Jackson, as it causes too many issues (though, as we can see the spring migration itself also does..). So, it turns out Jackson 2 -> 3 could be done in isolation after spring boot 4 migrationOpenSAML 5:
Migration to boot 4 currently seems to be a dead end due to Open SAML 5 FIPS compliance.
#Bonus research:
Java 25:
bcgit/bc-java#1287 (comment) - from this it seems that FIPS certification can take up to 14 months, at least this is how long it has taken before. This is actually very good information, as previously we just didn't know and could not set any expectations.