Fix UsernamePasswordAuthenticationTokenMixin to handle null credentials/details

Resolves #4698
This commit is contained in:
Greg Turnquist 2017-10-31 09:57:45 -05:00 committed by Rob Winch
parent 82adf744f5
commit 881cd0befb
2 changed files with 34 additions and 6 deletions

View File

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

View File

@ -30,10 +30,11 @@ import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User; 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 Jitendra Singh
* @author Greg Turnquist
* @since 4.2 * @since 4.2
*/ */
public class UsernamePasswordAuthenticationTokenMixinTests extends AbstractMixinTests { public class UsernamePasswordAuthenticationTokenMixinTests extends AbstractMixinTests {
@ -150,6 +151,20 @@ public class UsernamePasswordAuthenticationTokenMixinTests extends AbstractMixin
assertThat(token.getPrincipal()).isNotNull().isInstanceOf(NonUserPrincipal.class); 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() { private UsernamePasswordAuthenticationToken createToken() {
User user = createDefaultUser(); User user = createDefaultUser();
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(user, user.getPassword(), user.getAuthorities()); UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(user, user.getPassword(), user.getAuthorities());