Skip to content

Commit 35706ad

Browse files
fpavageaurwinch
authored andcommitted
Deserialize the principal in a neutral way
When the principal of the Authentication is an object, it is not necessarily an User: it could be another implementation of UserDetails, or even a completely unrelated type. Since the type of the object is serialized as a property and used by the deserialization anyway, there's no point in enforcing a stricter type.
1 parent 6fd9ff2 commit 35706ad

File tree

3 files changed

+50
-4
lines changed

3 files changed

+50
-4
lines changed

core/src/main/java/org/springframework/security/jackson2/UsernamePasswordAuthenticationTokenDeserializer.java

+1-2
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@
2626
import com.fasterxml.jackson.databind.node.MissingNode;
2727
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
2828
import org.springframework.security.core.GrantedAuthority;
29-
import org.springframework.security.core.userdetails.User;
3029

3130
import java.io.IOException;
3231
import java.util.List;
@@ -62,7 +61,7 @@ public UsernamePasswordAuthenticationToken deserialize(JsonParser jp, Deserializ
6261
JsonNode principalNode = readJsonNode(jsonNode, "principal");
6362
Object principal = null;
6463
if(principalNode.isObject()) {
65-
principal = mapper.readValue(principalNode.traverse(mapper), new TypeReference<User>() {});
64+
principal = mapper.readValue(principalNode.traverse(mapper), Object.class);
6665
} else {
6766
principal = principalNode.asText();
6867
}

core/src/test/java/org/springframework/security/jackson2/UsernamePasswordAuthenticationTokenMixinTests.java

+48
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,16 @@
1717
package org.springframework.security.jackson2;
1818

1919
import java.io.IOException;
20+
import java.util.ArrayList;
2021

22+
import com.fasterxml.jackson.annotation.JsonClassDescription;
2123
import com.fasterxml.jackson.core.JsonProcessingException;
2224
import org.json.JSONException;
2325
import org.junit.Test;
2426
import org.skyscreamer.jsonassert.JSONAssert;
2527

2628
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
29+
import org.springframework.security.core.GrantedAuthority;
2730
import org.springframework.security.core.authority.SimpleGrantedAuthority;
2831
import org.springframework.security.core.userdetails.User;
2932

@@ -49,6 +52,20 @@ public class UsernamePasswordAuthenticationTokenMixinTests extends AbstractMixin
4952
public static final String AUTHENTICATED_STRINGPRINCIPAL_JSON = AUTHENTICATED_JSON.replace( UserDeserializerTests.USER_JSON, "\"admin\"");
5053
// @formatter:on
5154

55+
// @formatter:off
56+
private static final String NON_USER_PRINCIPAL_JSON = "{"
57+
+ "\"@class\": \"org.springframework.security.jackson2.UsernamePasswordAuthenticationTokenMixinTests$NonUserPrincipal\", "
58+
+ "\"username\": \"admin\""
59+
+ "}";
60+
// @formatter:on
61+
62+
// @formatter:off
63+
private static final String AUTHENTICATED_NON_USER_PRINCIPAL_JSON = AUTHENTICATED_JSON
64+
.replace(UserDeserializerTests.USER_JSON, NON_USER_PRINCIPAL_JSON)
65+
.replaceAll(UserDeserializerTests.USER_PASSWORD, "null")
66+
.replace(SimpleGrantedAuthorityMixinTests.AUTHORITIES_ARRAYLIST_JSON, SimpleGrantedAuthorityMixinTests.NO_AUTHORITIES_ARRAYLIST_JSON);
67+
// @formatter:on
68+
5269
// @formatter:off
5370
private static final String UNAUTHENTICATED_STRINGPRINCIPAL_JSON = AUTHENTICATED_STRINGPRINCIPAL_JSON
5471
.replace("\"authenticated\": true, ", "\"authenticated\": false, ")
@@ -115,9 +132,40 @@ public void serializeAuthenticatedUsernamePasswordAuthenticationTokenMixinAfterE
115132
JSONAssert.assertEquals(AUTHENTICATED_JSON.replaceAll(UserDeserializerTests.USER_PASSWORD, "null"), actualJson, true);
116133
}
117134

135+
@Test
136+
public void serializeAuthenticatedUsernamePasswordAuthenticationTokenMixinWithNonUserPrincipalTest() throws JsonProcessingException, JSONException {
137+
NonUserPrincipal principal = new NonUserPrincipal();
138+
principal.setUsername("admin");
139+
UsernamePasswordAuthenticationToken token =
140+
new UsernamePasswordAuthenticationToken(principal, null, new ArrayList<GrantedAuthority>());
141+
String actualJson = mapper.writeValueAsString(token);
142+
JSONAssert.assertEquals(AUTHENTICATED_NON_USER_PRINCIPAL_JSON, actualJson, true);
143+
}
144+
145+
@Test
146+
public void deserializeAuthenticatedUsernamePasswordAuthenticationTokenWithNonUserPrincipalTest() throws IOException {
147+
UsernamePasswordAuthenticationToken token = mapper
148+
.readValue(AUTHENTICATED_NON_USER_PRINCIPAL_JSON, UsernamePasswordAuthenticationToken.class);
149+
assertThat(token).isNotNull();
150+
assertThat(token.getPrincipal()).isNotNull().isInstanceOf(NonUserPrincipal.class);
151+
}
152+
118153
private UsernamePasswordAuthenticationToken createToken() {
119154
User user = createDefaultUser();
120155
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(user, user.getPassword(), user.getAuthorities());
121156
return token;
122157
}
158+
159+
@JsonClassDescription
160+
public static class NonUserPrincipal {
161+
private String username;
162+
163+
public String getUsername() {
164+
return username;
165+
}
166+
167+
public void setUsername(String username) {
168+
this.username = username;
169+
}
170+
}
123171
}

web/src/main/java/org/springframework/security/web/jackson2/PreAuthenticatedAuthenticationTokenDeserializer.java

+1-2
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@
2020
import java.util.List;
2121

2222
import org.springframework.security.core.GrantedAuthority;
23-
import org.springframework.security.core.userdetails.User;
2423
import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken;
2524

2625
import com.fasterxml.jackson.core.JsonParser;
@@ -63,7 +62,7 @@ public PreAuthenticatedAuthenticationToken deserialize(JsonParser jp, Deserializ
6362
JsonNode principalNode = readJsonNode(jsonNode, "principal");
6463
Object principal = null;
6564
if(principalNode.isObject()) {
66-
principal = mapper.readValue(principalNode.traverse(mapper), new TypeReference<User>() {});
65+
principal = mapper.readValue(principalNode.traverse(mapper), Object.class);
6766
} else {
6867
principal = principalNode.asText();
6968
}

0 commit comments

Comments
 (0)