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 new file mode 100644 index 0000000000..48f1914436 --- /dev/null +++ b/web/src/main/java/org/springframework/security/web/jackson2/PreAuthenticatedAuthenticationTokenDeserializer.java @@ -0,0 +1,86 @@ +/* + * Copyright 2015-2016 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.security.web.jackson2; + +import java.io.IOException; +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; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.DeserializationContext; +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; + +/** + * Custom deserializer for {@link PreAuthenticatedAuthenticationToken}. At the time of deserialization + * it will invoke suitable constructor depending on the value of authenticated property. + * It will ensure that the token's state must not change. + *
+ * This deserializer is already registered with {@link PreAuthenticatedAuthenticationTokenMixin} but
+ * you can also registered it with your own mixin class.
+ *
+ * @author Jitendra Singh
+ * @see PreAuthenticatedAuthenticationTokenMixin
+ * @since 4.2
+ */
+class PreAuthenticatedAuthenticationTokenDeserializer extends JsonDeserializer>() {
+ });
+ if (authenticated) {
+ token = new PreAuthenticatedAuthenticationToken(principal, credentials, authorities);
+ } else {
+ token = new PreAuthenticatedAuthenticationToken(principal, credentials);
+ }
+ token.setDetails(readJsonNode(jsonNode, "details"));
+ return token;
+ }
+
+ private JsonNode readJsonNode(JsonNode jsonNode, String field) {
+ return jsonNode.has(field) ? jsonNode.get(field) : MissingNode.getInstance();
+ }
+}
diff --git a/web/src/main/java/org/springframework/security/web/jackson2/PreAuthenticatedAuthenticationTokenMixin.java b/web/src/main/java/org/springframework/security/web/jackson2/PreAuthenticatedAuthenticationTokenMixin.java
new file mode 100644
index 0000000000..6a339f39db
--- /dev/null
+++ b/web/src/main/java/org/springframework/security/web/jackson2/PreAuthenticatedAuthenticationTokenMixin.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2015-2016 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.security.web.jackson2;
+
+import org.springframework.security.jackson2.SecurityJackson2Modules;
+import org.springframework.security.jackson2.SimpleGrantedAuthorityMixin;
+
+import com.fasterxml.jackson.annotation.JsonAutoDetect;
+import com.fasterxml.jackson.annotation.JsonTypeInfo;
+import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
+
+/**
+ * This mixin class is used to serialize / deserialize
+ * {@link org.springframework.security.authentication.UsernamePasswordAuthenticationToken}. This class register
+ * a custom deserializer {@link PreAuthenticatedAuthenticationTokenDeserializer}.
+ *
+ * In order to use this mixin you'll need to add 3 more mixin classes.
+ *
+ *
+ *
+ *
+ * ObjectMapper mapper = new ObjectMapper();
+ * mapper.registerModule(new CoreJackson2Module());
+ *
+ * @author Jitendra Singh
+ * @see Webackson2Module
+ * @see SecurityJackson2Modules
+ * @since 4.2
+ */
+@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY, property = "@class")
+@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY, getterVisibility = JsonAutoDetect.Visibility.NONE,
+ isGetterVisibility = JsonAutoDetect.Visibility.NONE)
+@JsonDeserialize(using = PreAuthenticatedAuthenticationTokenDeserializer.class)
+abstract class PreAuthenticatedAuthenticationTokenMixin {
+}
diff --git a/web/src/main/java/org/springframework/security/web/jackson2/WebJackson2Module.java b/web/src/main/java/org/springframework/security/web/jackson2/WebJackson2Module.java
index d9408be734..de9adaf207 100644
--- a/web/src/main/java/org/springframework/security/web/jackson2/WebJackson2Module.java
+++ b/web/src/main/java/org/springframework/security/web/jackson2/WebJackson2Module.java
@@ -20,6 +20,7 @@ import javax.servlet.http.Cookie;
import org.springframework.security.jackson2.SecurityJackson2Modules;
import org.springframework.security.web.authentication.WebAuthenticationDetails;
+import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken;
import org.springframework.security.web.csrf.DefaultCsrfToken;
import org.springframework.security.web.savedrequest.DefaultSavedRequest;
import org.springframework.security.web.savedrequest.SavedCookie;
@@ -58,5 +59,6 @@ public class WebJackson2Module extends SimpleModule {
context.setMixInAnnotations(DefaultCsrfToken.class, DefaultCsrfTokenMixin.class);
context.setMixInAnnotations(DefaultSavedRequest.class, DefaultSavedRequestMixin.class);
context.setMixInAnnotations(WebAuthenticationDetails.class, WebAuthenticationDetailsMixin.class);
+ context.setMixInAnnotations(PreAuthenticatedAuthenticationToken.class, PreAuthenticatedAuthenticationTokenMixin.class);
}
}
diff --git a/web/src/test/java/org/springframework/security/web/jackson2/PreAuthenticatedAuthenticationTokenMixinTests.java b/web/src/test/java/org/springframework/security/web/jackson2/PreAuthenticatedAuthenticationTokenMixinTests.java
new file mode 100644
index 0000000000..a82b7d2025
--- /dev/null
+++ b/web/src/test/java/org/springframework/security/web/jackson2/PreAuthenticatedAuthenticationTokenMixinTests.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2015-2016 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.security.web.jackson2;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import org.json.JSONException;
+import org.junit.Before;
+import org.junit.Test;
+import org.skyscreamer.jsonassert.JSONAssert;
+import org.springframework.security.core.authority.AuthorityUtils;
+import org.springframework.security.jackson2.SimpleGrantedAuthorityMixinTests;
+import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+
+/**
+ * @author Rob Winch
+ * @since 4.2
+ */
+public class PreAuthenticatedAuthenticationTokenMixinTests extends AbstractMixinTests {
+ // @formatter:off
+ private static final String PREAUTH_JSON = "{"
+ + "\"@class\": \"org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken\","
+ + "\"principal\": \"principal\", "
+ + "\"credentials\": \"credentials\", "
+ + "\"authenticated\": true, "
+ + "\"details\": null, "
+ + "\"authorities\": "+ SimpleGrantedAuthorityMixinTests.AUTHORITIES_ARRAYLIST_JSON
+ + "}";
+ // @formatter:on
+
+ PreAuthenticatedAuthenticationToken expected;
+
+ @Before
+ public void setupExpected() {
+ expected = new PreAuthenticatedAuthenticationToken("principal", "credentials", AuthorityUtils.createAuthorityList("ROLE_USER"));
+ }
+
+ @Test
+ public void serializeWhenPrincipalCredentialsAuthoritiesThenSuccess() throws JsonProcessingException, JSONException {
+ String serializedJson = mapper.writeValueAsString(expected);
+ JSONAssert.assertEquals(PREAUTH_JSON, serializedJson, true);
+ }
+
+ @Test
+ public void deserializeAuthenticatedUsernamePasswordAuthenticationTokenMixinTest() throws Exception{
+ PreAuthenticatedAuthenticationToken deserialized = mapper
+ .readValue(PREAUTH_JSON, PreAuthenticatedAuthenticationToken.class);
+ assertThat(deserialized).isNotNull();
+ assertThat(deserialized.isAuthenticated()).isTrue();
+ assertThat(deserialized.getAuthorities()).isEqualTo(expected.getAuthorities());
+ }
+}