diff --git a/core/src/main/java/org/springframework/security/jackson2/UnmodifiableSetDeserializer.java b/core/src/main/java/org/springframework/security/jackson2/UnmodifiableSetDeserializer.java index 73cba239f78..97256a8de00 100644 --- a/core/src/main/java/org/springframework/security/jackson2/UnmodifiableSetDeserializer.java +++ b/core/src/main/java/org/springframework/security/jackson2/UnmodifiableSetDeserializer.java @@ -50,10 +50,10 @@ public Set deserialize(JsonParser jp, DeserializationContext ctxt) throws IOExce Iterator nodeIterator = arrayNode.iterator(); while (nodeIterator.hasNext()) { JsonNode elementNode = nodeIterator.next(); - resultSet.add(mapper.readValue(elementNode.toString(), Object.class)); + resultSet.add(mapper.readValue(elementNode.traverse(mapper), Object.class)); } } else { - resultSet.add(mapper.readValue(node.toString(), Object.class)); + resultSet.add(mapper.readValue(node.traverse(mapper), Object.class)); } } return Collections.unmodifiableSet(resultSet); diff --git a/core/src/main/java/org/springframework/security/jackson2/UsernamePasswordAuthenticationTokenDeserializer.java b/core/src/main/java/org/springframework/security/jackson2/UsernamePasswordAuthenticationTokenDeserializer.java index 450149e9bb2..1b6ef485ac5 100644 --- a/core/src/main/java/org/springframework/security/jackson2/UsernamePasswordAuthenticationTokenDeserializer.java +++ b/core/src/main/java/org/springframework/security/jackson2/UsernamePasswordAuthenticationTokenDeserializer.java @@ -26,7 +26,6 @@ import com.fasterxml.jackson.databind.node.MissingNode; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.GrantedAuthority; -import org.springframework.security.core.userdetails.User; import java.io.IOException; import java.util.List; @@ -62,13 +61,13 @@ public UsernamePasswordAuthenticationToken deserialize(JsonParser jp, Deserializ JsonNode principalNode = readJsonNode(jsonNode, "principal"); Object principal = null; if(principalNode.isObject()) { - principal = mapper.readValue(principalNode.toString(), new TypeReference() {}); + principal = mapper.readValue(principalNode.traverse(mapper), Object.class); } else { principal = principalNode.asText(); } Object credentials = readJsonNode(jsonNode, "credentials").asText(); List authorities = mapper.readValue( - readJsonNode(jsonNode, "authorities").toString(), new TypeReference>() { + readJsonNode(jsonNode, "authorities").traverse(mapper), new TypeReference>() { }); if (authenticated) { token = new UsernamePasswordAuthenticationToken(principal, credentials, authorities); diff --git a/core/src/test/java/org/springframework/security/jackson2/UsernamePasswordAuthenticationTokenMixinTests.java b/core/src/test/java/org/springframework/security/jackson2/UsernamePasswordAuthenticationTokenMixinTests.java index 966c4b29c00..d2977d6cfe9 100644 --- a/core/src/test/java/org/springframework/security/jackson2/UsernamePasswordAuthenticationTokenMixinTests.java +++ b/core/src/test/java/org/springframework/security/jackson2/UsernamePasswordAuthenticationTokenMixinTests.java @@ -17,13 +17,16 @@ package org.springframework.security.jackson2; import java.io.IOException; +import java.util.ArrayList; +import com.fasterxml.jackson.annotation.JsonClassDescription; import com.fasterxml.jackson.core.JsonProcessingException; import org.json.JSONException; import org.junit.Test; import org.skyscreamer.jsonassert.JSONAssert; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.userdetails.User; @@ -49,6 +52,20 @@ public class UsernamePasswordAuthenticationTokenMixinTests extends AbstractMixin public static final String AUTHENTICATED_STRINGPRINCIPAL_JSON = AUTHENTICATED_JSON.replace( UserDeserializerTests.USER_JSON, "\"admin\""); // @formatter:on + // @formatter:off + private static final String NON_USER_PRINCIPAL_JSON = "{" + + "\"@class\": \"org.springframework.security.jackson2.UsernamePasswordAuthenticationTokenMixinTests$NonUserPrincipal\", " + + "\"username\": \"admin\"" + + "}"; + // @formatter:on + + // @formatter:off + private static final String AUTHENTICATED_NON_USER_PRINCIPAL_JSON = AUTHENTICATED_JSON + .replace(UserDeserializerTests.USER_JSON, NON_USER_PRINCIPAL_JSON) + .replaceAll(UserDeserializerTests.USER_PASSWORD, "null") + .replace(SimpleGrantedAuthorityMixinTests.AUTHORITIES_ARRAYLIST_JSON, SimpleGrantedAuthorityMixinTests.NO_AUTHORITIES_ARRAYLIST_JSON); + // @formatter:on + // @formatter:off private static final String UNAUTHENTICATED_STRINGPRINCIPAL_JSON = AUTHENTICATED_STRINGPRINCIPAL_JSON .replace("\"authenticated\": true, ", "\"authenticated\": false, ") @@ -115,9 +132,40 @@ public void serializeAuthenticatedUsernamePasswordAuthenticationTokenMixinAfterE JSONAssert.assertEquals(AUTHENTICATED_JSON.replaceAll(UserDeserializerTests.USER_PASSWORD, "null"), actualJson, true); } + @Test + public void serializeAuthenticatedUsernamePasswordAuthenticationTokenMixinWithNonUserPrincipalTest() throws JsonProcessingException, JSONException { + NonUserPrincipal principal = new NonUserPrincipal(); + principal.setUsername("admin"); + UsernamePasswordAuthenticationToken token = + new UsernamePasswordAuthenticationToken(principal, null, new ArrayList()); + String actualJson = mapper.writeValueAsString(token); + JSONAssert.assertEquals(AUTHENTICATED_NON_USER_PRINCIPAL_JSON, actualJson, true); + } + + @Test + public void deserializeAuthenticatedUsernamePasswordAuthenticationTokenWithNonUserPrincipalTest() throws IOException { + UsernamePasswordAuthenticationToken token = mapper + .readValue(AUTHENTICATED_NON_USER_PRINCIPAL_JSON, UsernamePasswordAuthenticationToken.class); + assertThat(token).isNotNull(); + assertThat(token.getPrincipal()).isNotNull().isInstanceOf(NonUserPrincipal.class); + } + private UsernamePasswordAuthenticationToken createToken() { User user = createDefaultUser(); UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(user, user.getPassword(), user.getAuthorities()); return token; } + + @JsonClassDescription + public static class NonUserPrincipal { + private String username; + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + } } diff --git a/web/src/main/java/org/springframework/security/web/jackson2/PreAuthenticatedAuthenticationTokenDeserializer.java b/web/src/main/java/org/springframework/security/web/jackson2/PreAuthenticatedAuthenticationTokenDeserializer.java index 48f19144363..f58c2f0fb55 100644 --- a/web/src/main/java/org/springframework/security/web/jackson2/PreAuthenticatedAuthenticationTokenDeserializer.java +++ b/web/src/main/java/org/springframework/security/web/jackson2/PreAuthenticatedAuthenticationTokenDeserializer.java @@ -20,7 +20,6 @@ import java.util.List; import org.springframework.security.core.GrantedAuthority; -import org.springframework.security.core.userdetails.User; import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken; import com.fasterxml.jackson.core.JsonParser; @@ -63,13 +62,13 @@ public PreAuthenticatedAuthenticationToken deserialize(JsonParser jp, Deserializ JsonNode principalNode = readJsonNode(jsonNode, "principal"); Object principal = null; if(principalNode.isObject()) { - principal = mapper.readValue(principalNode.toString(), new TypeReference() {}); + principal = mapper.readValue(principalNode.traverse(mapper), Object.class); } else { principal = principalNode.asText(); } Object credentials = readJsonNode(jsonNode, "credentials").asText(); List authorities = mapper.readValue( - readJsonNode(jsonNode, "authorities").toString(), new TypeReference>() { + readJsonNode(jsonNode, "authorities").traverse(mapper), new TypeReference>() { }); if (authenticated) { token = new PreAuthenticatedAuthenticationToken(principal, credentials, authorities);