瀏覽代碼

Fix UsernamePasswordAuthenticationTokenMixin to handle null credentials/details

Resolves #4698
Greg Turnquist 7 年之前
父節點
當前提交
881cd0befb

+ 18 - 5
core/src/main/java/org/springframework/security/jackson2/UsernamePasswordAuthenticationTokenDeserializer.java

@@ -16,6 +16,9 @@
 
 package org.springframework.security.jackson2;
 
+import java.io.IOException;
+import java.util.List;
+
 import com.fasterxml.jackson.core.JsonParser;
 import com.fasterxml.jackson.core.JsonProcessingException;
 import com.fasterxml.jackson.core.type.TypeReference;
@@ -24,12 +27,10 @@ import com.fasterxml.jackson.databind.JsonDeserializer;
 import com.fasterxml.jackson.databind.JsonNode;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import com.fasterxml.jackson.databind.node.MissingNode;
+
 import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
 import org.springframework.security.core.GrantedAuthority;
 
-import java.io.IOException;
-import java.util.List;
-
 /**
  * Custom deserializer for {@link UsernamePasswordAuthenticationToken}. At the time of deserialization
  * it will invoke suitable constructor depending on the value of <b>authenticated</b> property.
@@ -39,6 +40,7 @@ import java.util.List;
  * you can also registered it with your own mixin class.
  *
  * @author Jitendra Singh
+ * @author Greg Turnquist
  * @see UsernamePasswordAuthenticationTokenMixin
  * @since 4.2
  */
@@ -65,7 +67,13 @@ class UsernamePasswordAuthenticationTokenDeserializer extends JsonDeserializer<U
 		} else {
 			principal = principalNode.asText();
 		}
-		Object credentials = readJsonNode(jsonNode, "credentials").asText();
+		JsonNode credentialsNode = readJsonNode(jsonNode, "credentials");
+		Object credentials;
+		if (credentialsNode.isNull()) {
+			credentials = null;
+		} else {
+			credentials = credentialsNode.asText();
+		}
 		List<GrantedAuthority> authorities = mapper.readValue(
 				readJsonNode(jsonNode, "authorities").traverse(mapper), new TypeReference<List<GrantedAuthority>>() {
 		});
@@ -74,7 +82,12 @@ class UsernamePasswordAuthenticationTokenDeserializer extends JsonDeserializer<U
 		} else {
 			token = new UsernamePasswordAuthenticationToken(principal, credentials);
 		}
-		token.setDetails(readJsonNode(jsonNode, "details"));
+		JsonNode detailsNode = readJsonNode(jsonNode, "details");
+		if (detailsNode.isNull()) {
+			token.setDetails(null);
+		} else {
+			token.setDetails(detailsNode);
+		}
 		return token;
 	}
 

+ 16 - 1
core/src/test/java/org/springframework/security/jackson2/UsernamePasswordAuthenticationTokenMixinTests.java

@@ -30,10 +30,11 @@ import org.springframework.security.core.GrantedAuthority;
 import org.springframework.security.core.authority.SimpleGrantedAuthority;
 import org.springframework.security.core.userdetails.User;
 
-import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.*;
 
 /**
  * @author Jitendra Singh
+ * @author Greg Turnquist
  * @since 4.2
  */
 public class UsernamePasswordAuthenticationTokenMixinTests extends AbstractMixinTests {
@@ -150,6 +151,20 @@ public class UsernamePasswordAuthenticationTokenMixinTests extends AbstractMixin
 		assertThat(token.getPrincipal()).isNotNull().isInstanceOf(NonUserPrincipal.class);
 	}
 
+	@Test
+	public void serializingThenDeserializingWithNoCredentialsOrDetailsShouldWork() throws IOException {
+		// given
+		UsernamePasswordAuthenticationToken original = new UsernamePasswordAuthenticationToken("Frodo", null);
+
+		// when
+		String serialized = this.mapper.writeValueAsString(original);
+		UsernamePasswordAuthenticationToken deserialized = this.mapper.readValue(serialized, UsernamePasswordAuthenticationToken.class);
+
+		// then
+		assertThat(deserialized).isEqualTo(original);
+	}
+
+
 	private UsernamePasswordAuthenticationToken createToken() {
 		User user = createDefaultUser();
 		UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(user, user.getPassword(), user.getAuthorities());