diff --git a/web/src/main/java/org/springframework/security/web/jackson2/SwitchUserGrantedAuthorityMixIn.java b/web/src/main/java/org/springframework/security/web/jackson2/SwitchUserGrantedAuthorityMixIn.java index 4fff7ffdc4..f61b8a05bf 100644 --- a/web/src/main/java/org/springframework/security/web/jackson2/SwitchUserGrantedAuthorityMixIn.java +++ b/web/src/main/java/org/springframework/security/web/jackson2/SwitchUserGrantedAuthorityMixIn.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2024 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -30,6 +30,7 @@ * * @author Markus Heiden * @since 6.3 + * @see WebJackson2Module * @see WebServletJackson2Module * @see org.springframework.security.jackson2.SecurityJackson2Modules */ diff --git a/web/src/main/java/org/springframework/security/web/jackson2/WebJackson2Module.java b/web/src/main/java/org/springframework/security/web/jackson2/WebJackson2Module.java index 87daedcc40..b8cee4fee0 100644 --- a/web/src/main/java/org/springframework/security/web/jackson2/WebJackson2Module.java +++ b/web/src/main/java/org/springframework/security/web/jackson2/WebJackson2Module.java @@ -1,5 +1,5 @@ /* - * Copyright 2015-2016 the original author or authors. + * Copyright 2015-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,14 +21,16 @@ import org.springframework.security.jackson2.SecurityJackson2Modules; import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken; +import org.springframework.security.web.authentication.switchuser.SwitchUserGrantedAuthority; import org.springframework.security.web.csrf.DefaultCsrfToken; /** * Jackson module for spring-security-web. This module register - * {@link DefaultCsrfTokenMixin} and {@link PreAuthenticatedAuthenticationTokenMixin}. If - * no default typing enabled by default then it'll enable it because typing info is needed - * to properly serialize/deserialize objects. In order to use this module just add this - * module into your ObjectMapper configuration. + * {@link DefaultCsrfTokenMixin}, {@link PreAuthenticatedAuthenticationTokenMixin} and + * {@link SwitchUserGrantedAuthorityMixIn}. If no default typing enabled by default then + * it'll enable it because typing info is needed to properly serialize/deserialize + * objects. In order to use this module just add this module into your ObjectMapper + * configuration. * *
* ObjectMapper mapper = new ObjectMapper(); @@ -53,6 +55,7 @@ public void setupModule(SetupContext context) { context.setMixInAnnotations(DefaultCsrfToken.class, DefaultCsrfTokenMixin.class); context.setMixInAnnotations(PreAuthenticatedAuthenticationToken.class, PreAuthenticatedAuthenticationTokenMixin.class); + context.setMixInAnnotations(SwitchUserGrantedAuthority.class, SwitchUserGrantedAuthorityMixIn.class); } } diff --git a/web/src/test/java/org/springframework/security/web/jackson2/SwitchUserGrantedAuthorityMixInTests.java b/web/src/test/java/org/springframework/security/web/jackson2/SwitchUserGrantedAuthorityMixInTests.java index 703811658c..70bba02513 100644 --- a/web/src/test/java/org/springframework/security/web/jackson2/SwitchUserGrantedAuthorityMixInTests.java +++ b/web/src/test/java/org/springframework/security/web/jackson2/SwitchUserGrantedAuthorityMixInTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2024 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,14 +16,20 @@ package org.springframework.security.web.jackson2; +import java.util.stream.Stream; + +import com.fasterxml.jackson.databind.ObjectMapper; import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; import org.skyscreamer.jsonassert.JSONAssert; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.Authentication; import org.springframework.security.core.authority.AuthorityUtils; -import org.springframework.security.jackson2.AbstractMixinTests; +import org.springframework.security.jackson2.CoreJackson2Module; +import org.springframework.security.jackson2.SecurityJackson2Modules; import org.springframework.security.jackson2.SimpleGrantedAuthorityMixinTests; import org.springframework.security.web.authentication.switchuser.SwitchUserGrantedAuthority; @@ -33,7 +39,7 @@ * @author Markus Heiden * @since 6.3 */ -public class SwitchUserGrantedAuthorityMixInTests extends AbstractMixinTests { +public class SwitchUserGrantedAuthorityMixInTests { // language=JSON private static final String SWITCH_JSON = """ @@ -53,22 +59,42 @@ public class SwitchUserGrantedAuthorityMixInTests extends AbstractMixinTests { private Authentication source; + static Streammappers() { + ObjectMapper securityJackson2ModulesMapper = new ObjectMapper(); + ClassLoader classLoader = SwitchUserGrantedAuthorityMixInTests.class.getClassLoader(); + securityJackson2ModulesMapper.registerModules(SecurityJackson2Modules.getModules(classLoader)); + + ObjectMapper webJackson2ModuleMapper = new ObjectMapper(); + webJackson2ModuleMapper.registerModule(new CoreJackson2Module()); + webJackson2ModuleMapper.registerModule(new WebJackson2Module()); + + ObjectMapper webServletJackson2ModuleMapper = new ObjectMapper(); + webServletJackson2ModuleMapper.registerModule(new CoreJackson2Module()); + webServletJackson2ModuleMapper.registerModule(new WebServletJackson2Module()); + + return Stream.of(Arguments.of(securityJackson2ModulesMapper), Arguments.of(webJackson2ModuleMapper), + Arguments.of(webServletJackson2ModuleMapper)); + } + @BeforeEach public void setUp() { this.source = new UsernamePasswordAuthenticationToken("principal", "credentials", AuthorityUtils.createAuthorityList("ROLE_USER")); } - @Test - public void serializeWhenPrincipalCredentialsAuthoritiesThenSuccess() throws Exception { + @ParameterizedTest + @MethodSource("mappers") + public void serializeWhenPrincipalCredentialsAuthoritiesThenSuccess(ObjectMapper mapper) throws Exception { SwitchUserGrantedAuthority expected = new SwitchUserGrantedAuthority("switched", this.source); - String serializedJson = this.mapper.writeValueAsString(expected); + String serializedJson = mapper.writeValueAsString(expected); JSONAssert.assertEquals(SWITCH_JSON, serializedJson, true); } - @Test - public void deserializeWhenSourceIsUsernamePasswordAuthenticationTokenThenSuccess() throws Exception { - SwitchUserGrantedAuthority deserialized = this.mapper.readValue(SWITCH_JSON, SwitchUserGrantedAuthority.class); + @ParameterizedTest + @MethodSource("mappers") + public void deserializeWhenSourceIsUsernamePasswordAuthenticationTokenThenSuccess(ObjectMapper mapper) + throws Exception { + SwitchUserGrantedAuthority deserialized = mapper.readValue(SWITCH_JSON, SwitchUserGrantedAuthority.class); assertThat(deserialized).isNotNull(); assertThat(deserialized.getAuthority()).isEqualTo("switched"); assertThat(deserialized.getSource()).isEqualTo(this.source);