Browse Source

Add SwitchUserGrantedAuthority to Web Jackson Module

Closes gh-17041

Signed-off-by: John Niang <johnniang@foxmail.com>
John Niang 3 months ago
parent
commit
9ba5c7b2ce

+ 2 - 1
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 @@ import org.springframework.security.web.authentication.switchuser.SwitchUserGran
  *
  * @author Markus Heiden
  * @since 6.3
+ * @see WebJackson2Module
  * @see WebServletJackson2Module
  * @see org.springframework.security.jackson2.SecurityJackson2Modules
  */

+ 8 - 5
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 com.fasterxml.jackson.databind.module.SimpleModule;
 
 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.
  *
  * <pre>
  *     ObjectMapper mapper = new ObjectMapper();
@@ -53,6 +55,7 @@ public class WebJackson2Module extends SimpleModule {
 		context.setMixInAnnotations(DefaultCsrfToken.class, DefaultCsrfTokenMixin.class);
 		context.setMixInAnnotations(PreAuthenticatedAuthenticationToken.class,
 				PreAuthenticatedAuthenticationTokenMixin.class);
+		context.setMixInAnnotations(SwitchUserGrantedAuthority.class, SwitchUserGrantedAuthorityMixIn.class);
 	}
 
 }

+ 36 - 10
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 @@ import static org.assertj.core.api.Assertions.assertThat;
  * @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 Stream<Arguments> mappers() {
+		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);