Make Jackson operational.

Resolves https://github.com/spring-projects/spring-session/issues/913
This commit is contained in:
Greg Turnquist
2017-10-25 16:35:59 -05:00
parent fde5a85f49
commit 7a4e14cfbf
6 changed files with 188 additions and 100 deletions

View File

@@ -512,15 +512,14 @@
<artifactId>reactor-core</artifactId>
<optional>true</optional>
</dependency>
<!-- Test dependencies -->
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-core</artifactId>
<scope>test</scope>
</dependency>
<!-- Test dependencies -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>

View File

@@ -22,7 +22,6 @@ import java.util.Set;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.bson.Document;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.core.convert.converter.GenericConverter;
import org.springframework.data.domain.Sort;

View File

@@ -17,13 +17,16 @@ package org.springframework.session.data.mongo;
import java.io.IOException;
import java.util.Collections;
import java.util.HashMap;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.bson.Document;
import org.bson.json.JsonMode;
import org.bson.json.JsonWriterSettings;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.security.jackson2.SecurityJackson2Modules;
import org.springframework.session.FindByIndexNameSessionRepository;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
@@ -85,9 +88,27 @@ public class JacksonMongoSessionConverter extends AbstractMongoSessionConverter
objectMapper.setPropertyNamingStrategy(new MongoIdNamingStrategy());
objectMapper.registerModules(SecurityJackson2Modules.getModules(getClass().getClassLoader()));
objectMapper.addMixIn(MongoSession.class, MongoSessionMixin.class);
objectMapper.addMixIn(HashMap.class, HashMapMixin.class);
return objectMapper;
}
/**
* Used to whitelist {@link MongoSession} for {@link SecurityJackson2Modules}.
*/
private static class MongoSessionMixin {
// Nothing special
}
/**
* Used to whitelist {@link HashMap} for {@link SecurityJackson2Modules}.
*/
private static class HashMapMixin {
// Nothing special
}
@Override
protected DBObject convert(MongoSession source) {
@@ -103,8 +124,8 @@ public class JacksonMongoSessionConverter extends AbstractMongoSessionConverter
@Override
protected MongoSession convert(Document source) {
String json = JSON.serialize(source);
String json = source.toJson(JsonWriterSettings.builder().outputMode(JsonMode.RELAXED).build());
try {
return this.objectMapper.readValue(json, MongoSession.class);
} catch (IOException e) {

View File

@@ -0,0 +1,145 @@
/*
* Copyright 2017 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.session.data.mongo;
import static org.assertj.core.api.Assertions.*;
import java.time.Duration;
import org.bson.Document;
import org.junit.Test;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextImpl;
import org.springframework.session.FindByIndexNameSessionRepository;
import com.mongodb.DBObject;
/**
* @author Greg Turnquist
*/
public abstract class AbstractMongoSessionConverterTest {
abstract AbstractMongoSessionConverter getMongoSessionConverter();
@Test
public void verifyRoundTripSerialization() throws Exception {
// given
MongoSession toSerialize = new MongoSession();
toSerialize.setAttribute("username", "john_the_springer");
// when
DBObject dbObject = convertToDBObject(toSerialize);
MongoSession deserialized = convertToSession(dbObject);
// then
assertThat(deserialized).isEqualToComparingFieldByField(toSerialize);
}
@Test
public void verifyRoundTripSecuritySerialization() {
// given
MongoSession toSerialize = new MongoSession();
String principalName = "john_the_springer";
SecurityContextImpl context = new SecurityContextImpl();
context.setAuthentication(
new UsernamePasswordAuthenticationToken(principalName, null));
toSerialize.setAttribute("SPRING_SECURITY_CONTEXT", context);
// when
DBObject serialized = convertToDBObject(toSerialize);
MongoSession deserialized = convertToSession(serialized);
// then
assertThat(deserialized).isEqualToComparingOnlyGivenFields(toSerialize,
"id", "createdMillis", "accessedMillis", "intervalSeconds", "expireAt");
SecurityContextImpl springSecurityContextBefore = toSerialize.getAttribute("SPRING_SECURITY_CONTEXT");
SecurityContextImpl springSecurityContextAfter = deserialized.getAttribute("SPRING_SECURITY_CONTEXT");
assertThat(springSecurityContextBefore).isEqualToComparingOnlyGivenFields(springSecurityContextAfter,
"authentication.principal", "authentication.authorities", "authentication.authenticated");
assertThat(springSecurityContextAfter.getAuthentication().getPrincipal()).isEqualTo("john_the_springer");
assertThat(springSecurityContextAfter.getAuthentication().getCredentials()).isNull();
}
@Test
public void shouldExtractPrincipalNameFromAttributes() throws Exception {
// given
MongoSession toSerialize = new MongoSession();
String principalName = "john_the_springer";
toSerialize.setAttribute(
FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME,
principalName);
// when
DBObject dbObject = convertToDBObject(toSerialize);
// then
assertThat(dbObject.get("principal")).isEqualTo(principalName);
}
@Test
public void shouldExtractPrincipalNameFromAuthentication() throws Exception {
// given
MongoSession toSerialize = new MongoSession();
String principalName = "john_the_springer";
SecurityContextImpl context = new SecurityContextImpl();
context.setAuthentication(
new UsernamePasswordAuthenticationToken(principalName, null));
toSerialize.setAttribute("SPRING_SECURITY_CONTEXT", context);
// when
DBObject dbObject = convertToDBObject(toSerialize);
// then
assertThat(dbObject.get("principal")).isEqualTo(principalName);
}
@Test
public void sessionWrapperWithNoMaxIntervalShouldFallbackToDefaultValues() {
// given
MongoSession toSerialize = new MongoSession();
DBObject dbObject = convertToDBObject(toSerialize);
Document document = new Document(dbObject.toMap());
document.remove("interval");
// when
MongoSession convertedSession = getMongoSessionConverter().convert(document);
// then
assertThat(convertedSession.getMaxInactiveInterval()).isEqualTo(Duration.ofMinutes(30));
}
MongoSession convertToSession(DBObject session) {
return (MongoSession) getMongoSessionConverter().convert(session,
TypeDescriptor.valueOf(DBObject.class),
TypeDescriptor.valueOf(MongoSession.class));
}
DBObject convertToDBObject(MongoSession session) {
return (DBObject) getMongoSessionConverter().convert(session,
TypeDescriptor.valueOf(MongoSession.class),
TypeDescriptor.valueOf(DBObject.class));
}
}

View File

@@ -18,7 +18,6 @@ package org.springframework.session.data.mongo;
import static org.assertj.core.api.Assertions.*;
import org.junit.Test;
import org.springframework.data.mongodb.core.query.Query;
import com.mongodb.DBObject;
@@ -27,9 +26,14 @@ import com.mongodb.DBObject;
* @author Jakub Kubrynski
* @author Greg Turnquist
*/
public class JacksonMongoSessionConverterTest {
public class JacksonMongoSessionConverterTest extends AbstractMongoSessionConverterTest {
JacksonMongoSessionConverter sut = new JacksonMongoSessionConverter();
JacksonMongoSessionConverter mongoSessionConverter = new JacksonMongoSessionConverter();
@Override
AbstractMongoSessionConverter getMongoSessionConverter() {
return this.mongoSessionConverter;
}
@Test
public void shouldSaveIdField() throws Exception {
@@ -38,7 +42,7 @@ public class JacksonMongoSessionConverterTest {
MongoSession session = new MongoSession();
//when
DBObject convert = this.sut.convert(session);
DBObject convert = this.mongoSessionConverter.convert(session);
//then
assertThat(convert.get("_id")).isEqualTo(session.getId());
@@ -49,9 +53,11 @@ public class JacksonMongoSessionConverterTest {
public void shouldQueryAgainstAttribute() throws Exception {
//when
Query cart = this.sut.getQueryForIndex("cart", "my-cart");
Query cart = this.mongoSessionConverter.getQueryForIndex("cart", "my-cart");
//then
assertThat(cart.getQueryObject().get("attrs.cart")).isEqualTo("my-cart");
}
}

View File

@@ -15,31 +15,27 @@
*/
package org.springframework.session.data.mongo;
import static org.assertj.core.api.Assertions.*;
import java.time.Duration;
import org.bson.Document;
import org.junit.Test;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.core.serializer.support.DeserializingConverter;
import org.springframework.core.serializer.support.SerializingConverter;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextImpl;
import org.springframework.session.FindByIndexNameSessionRepository;
import com.mongodb.DBObject;
/**
* @author Jakub Kubrynski
* @author Rob Winch
* @author Greg Turnquist
*/
public class JdkMongoSessionConverterTest {
public class JdkMongoSessionConverterTest extends AbstractMongoSessionConverterTest {
Duration inactiveInterval = Duration.ofMinutes(30);
JdkMongoSessionConverter mongoSessionConverter = new JdkMongoSessionConverter(inactiveInterval);
@Override
AbstractMongoSessionConverter getMongoSessionConverter() {
return this.mongoSessionConverter;
}
@Test(expected = IllegalArgumentException.class)
public void constructorNullSerializer() {
new JdkMongoSessionConverter(null, new DeserializingConverter(), inactiveInterval);
@@ -49,82 +45,4 @@ public class JdkMongoSessionConverterTest {
public void constructorNullDeserializer() {
new JdkMongoSessionConverter(new SerializingConverter(), null, inactiveInterval);
}
@Test
public void verifyRoundTripSerialization() throws Exception {
// given
MongoSession toSerialize = new MongoSession();
toSerialize.setAttribute("username", "john_the_springer");
// when
DBObject dbObject = convertToDBObject(toSerialize);
MongoSession deserialized = convertToSession(dbObject);
// then
assertThat(deserialized).isEqualToComparingFieldByField(toSerialize);
}
@Test
public void shouldExtractPrincipalNameFromAttributes() throws Exception {
// given
MongoSession toSerialize = new MongoSession();
String principalName = "john_the_springer";
toSerialize.setAttribute(
FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME,
principalName);
// when
DBObject dbObject = convertToDBObject(toSerialize);
// then
assertThat(dbObject.get("principal")).isEqualTo(principalName);
}
@Test
public void shouldExtractPrincipalNameFromAuthentication() throws Exception {
// given
MongoSession toSerialize = new MongoSession();
String principalName = "john_the_springer";
SecurityContextImpl context = new SecurityContextImpl();
context.setAuthentication(
new UsernamePasswordAuthenticationToken(principalName, null));
toSerialize.setAttribute("SPRING_SECURITY_CONTEXT", context);
// when
DBObject dbObject = convertToDBObject(toSerialize);
// then
assertThat(dbObject.get("principal")).isEqualTo(principalName);
}
@Test
public void sessionWrapperWithNoMaxIntervalShouldFallbackToDefaultValues() {
// given
MongoSession toSerialize = new MongoSession();
DBObject dbObject = convertToDBObject(toSerialize);
Document document = new Document(dbObject.toMap());
document.remove("interval");
// when
MongoSession convertedSession = this.mongoSessionConverter.convert(document);
// then
assertThat(convertedSession.getMaxInactiveInterval()).isEqualTo(Duration.ofMinutes(30));
}
MongoSession convertToSession(DBObject session) {
return (MongoSession) this.mongoSessionConverter.convert(session,
TypeDescriptor.valueOf(DBObject.class),
TypeDescriptor.valueOf(MongoSession.class));
}
DBObject convertToDBObject(MongoSession session) {
return (DBObject) this.mongoSessionConverter.convert(session,
TypeDescriptor.valueOf(MongoSession.class),
TypeDescriptor.valueOf(DBObject.class));
}
}