JSonSerializerWithAccessFilterUnitTest
This commit is contained in:
		| @@ -6,7 +6,6 @@ import com.fasterxml.jackson.databind.JsonSerializer; | ||||
| import com.fasterxml.jackson.databind.SerializerProvider; | ||||
| import org.apache.commons.lang3.NotImplementedException; | ||||
| import org.hostsharing.hsadminng.security.SecurityUtils; | ||||
| import org.hostsharing.hsadminng.service.dto.CustomerDTO; | ||||
| import org.springframework.boot.jackson.JsonComponent; | ||||
|  | ||||
| import java.io.IOException; | ||||
| @@ -18,20 +17,22 @@ import java.lang.reflect.Method; | ||||
| public class JSonSerializerWithAccessFilter extends JsonSerializer<Object> { | ||||
|  | ||||
|     @Override | ||||
|     public void serialize(Object dto, JsonGenerator jsonGenerator, | ||||
|                           SerializerProvider serializerProvider) throws IOException { | ||||
|     public void serialize(final Object dto, final JsonGenerator jsonGenerator, | ||||
|                           final SerializerProvider serializerProvider) throws IOException { | ||||
|  | ||||
|         // TODO: move the implementation to an (if necessary, inner) class | ||||
|         jsonGenerator.writeStartObject(); | ||||
|         for (Field prop : CustomerDTO.class.getDeclaredFields()) { | ||||
|         for (Field prop : dto.getClass().getDeclaredFields()) { | ||||
|             toJSon(dto, jsonGenerator, prop); | ||||
|         } | ||||
|  | ||||
|         jsonGenerator.writeEndObject(); | ||||
|     } | ||||
|  | ||||
|     private void toJSon(Object dto, JsonGenerator jsonGenerator, Field prop) throws IOException { | ||||
|     private void toJSon(final Object dto, final JsonGenerator jsonGenerator, final Field prop) throws IOException { | ||||
|         if (getLoginUserRole().isAllowedToRead(prop)) { | ||||
|             final String fieldName = prop.getName(); | ||||
|             // TODO: maybe replace by serializerProvider.defaultSerialize...()? | ||||
|             if (Integer.class.isAssignableFrom(prop.getType()) || int.class.isAssignableFrom(prop.getType())) { | ||||
|                 jsonGenerator.writeNumberField(fieldName, (int) get(dto, prop)); | ||||
|             } else if (Long.class.isAssignableFrom(prop.getType()) || long.class.isAssignableFrom(prop.getType())) { | ||||
| @@ -44,25 +45,16 @@ public class JSonSerializerWithAccessFilter extends JsonSerializer<Object> { | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private Object get(Object dto, Field field) { | ||||
|     private Object get(final Object dto, final Field field) { | ||||
|         try { | ||||
|             field.setAccessible(true); | ||||
|             return field.get(dto); | ||||
|         } catch (IllegalAccessException e) { | ||||
|             throw new RuntimeException(e); | ||||
|             throw new RuntimeException("getting field " + field + " failed", e); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private Role getLoginUserRole() { | ||||
|         return SecurityUtils.getCurrentUserLogin().map(u -> Role.valueOf(u.toUpperCase())).orElse(Role.ANYBODY); | ||||
|     } | ||||
|  | ||||
|     private Object invoke(Object dto, Method method) { | ||||
|         try { | ||||
|             return method.invoke(dto); | ||||
|         } catch (IllegalAccessException | InvocationTargetException e) { | ||||
|             throw new RuntimeException(e); | ||||
|         } | ||||
|     } | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -0,0 +1,114 @@ | ||||
| package org.hostsharing.hsadminng.service.accessfilter; | ||||
|  | ||||
| import com.fasterxml.jackson.core.JsonGenerator; | ||||
| import org.apache.commons.lang3.NotImplementedException; | ||||
| import org.apache.commons.lang3.RandomStringUtils; | ||||
| import org.apache.commons.lang3.RandomUtils; | ||||
| import org.junit.Before; | ||||
| import org.junit.Rule; | ||||
| import org.junit.Test; | ||||
| import org.mockito.Mock; | ||||
| import org.mockito.junit.MockitoJUnit; | ||||
| import org.mockito.junit.MockitoRule; | ||||
|  | ||||
| import java.io.IOException; | ||||
|  | ||||
| import static org.assertj.core.api.Assertions.assertThat; | ||||
| import static org.assertj.core.api.Assertions.catchThrowable; | ||||
| import static org.hostsharing.hsadminng.service.accessfilter.MockSecurityContext.givenLoginUserWithRole; | ||||
| import static org.mockito.Mockito.never; | ||||
| import static org.mockito.Mockito.verify; | ||||
|  | ||||
| public class JSonSerializerWithAccessFilterUnitTest { | ||||
|  | ||||
|     @Rule | ||||
|     public MockitoRule mockitoRule = MockitoJUnit.rule(); | ||||
|  | ||||
|     @Mock | ||||
|     public JsonGenerator jsonGenerator; | ||||
|  | ||||
|     private final GivenDto givenDTO = createSampleDto(); | ||||
|  | ||||
|     @Before | ||||
|     public void init() { | ||||
|         givenLoginUserWithRole(Role.ANY_CUSTOMER_USER); | ||||
|     } | ||||
|  | ||||
|     @Test | ||||
|     public void shouldSerializeStringField() throws IOException { | ||||
|     // when | ||||
|         new JSonSerializerWithAccessFilter().serialize(givenDTO, jsonGenerator, null); | ||||
|  | ||||
|         // then | ||||
|         verify(jsonGenerator).writeStringField("openStringField", givenDTO.openStringField); | ||||
|     } | ||||
|  | ||||
|     @Test | ||||
|     public void shouldSerializeRestrictedFieldIfRequiredRoleIsCoveredByUser() throws IOException { | ||||
|  | ||||
|         // given | ||||
|         givenLoginUserWithRole(Role.FINANCIAL_CONTACT); | ||||
|  | ||||
|         // when | ||||
|         new JSonSerializerWithAccessFilter().serialize(givenDTO, jsonGenerator, null); | ||||
|  | ||||
|         // then | ||||
|        verify(jsonGenerator).writeStringField("restrictedField", givenDTO.restrictedField); | ||||
|     } | ||||
|  | ||||
|     @Test | ||||
|     public void shouldNotSerializeRestrictedFieldIfRequiredRoleIsNotCoveredByUser() throws IOException { | ||||
|  | ||||
|         // given | ||||
|         givenLoginUserWithRole(Role.ANY_CUSTOMER_USER); | ||||
|  | ||||
|         // when | ||||
|         new JSonSerializerWithAccessFilter().serialize(givenDTO, jsonGenerator, null); | ||||
|  | ||||
|         // then | ||||
|         verify(jsonGenerator, never()).writeStringField("restrictedField", givenDTO.restrictedField); | ||||
|     } | ||||
|  | ||||
|     @Test | ||||
|     public void shouldThrowExceptionForUnimplementedFieldType() throws IOException { | ||||
|  | ||||
|         // given | ||||
|         class Arbitrary {} | ||||
|         class GivenDtoWithUnimplementedFieldType { | ||||
|             @AccessFor(read = Role.ANYBODY) | ||||
|             Arbitrary fieldWithUnimplementedType; | ||||
|         } | ||||
|         final GivenDtoWithUnimplementedFieldType givenDto = new GivenDtoWithUnimplementedFieldType(); | ||||
|  | ||||
|         // when | ||||
|         Throwable actual = catchThrowable(() -> new JSonSerializerWithAccessFilter().serialize(givenDto, jsonGenerator, null)); | ||||
|  | ||||
|         // then | ||||
|         assertThat(actual).isInstanceOf(NotImplementedException.class); | ||||
|     } | ||||
|  | ||||
|     // --- fixture code below --- | ||||
|  | ||||
|     private GivenDto createSampleDto() { | ||||
|         final GivenDto dto = new GivenDto(); | ||||
|         dto.restrictedField = RandomStringUtils.randomAlphabetic(10); | ||||
|         dto.openStringField = RandomStringUtils.randomAlphabetic(10); | ||||
|         dto.openIntegerField = RandomUtils.nextInt(); | ||||
|         dto.openLongField = RandomUtils.nextLong(); | ||||
|         return dto; | ||||
|     } | ||||
|  | ||||
|     private static class GivenDto { | ||||
|         @AccessFor(read = {Role.TECHNICAL_CONTACT, Role.FINANCIAL_CONTACT}) | ||||
|         String restrictedField; | ||||
|  | ||||
|         @AccessFor(read = Role.ANYBODY) | ||||
|         String openStringField; | ||||
|  | ||||
|         @AccessFor(read = Role.ANYBODY) | ||||
|         Integer openIntegerField; | ||||
|  | ||||
|         @AccessFor(read = Role.ANYBODY) | ||||
|         Long openLongField; | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,24 @@ | ||||
| package org.hostsharing.hsadminng.service.accessfilter; | ||||
|  | ||||
| import org.hostsharing.hsadminng.security.SecurityUtils; | ||||
| import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; | ||||
| import org.springframework.security.core.context.SecurityContext; | ||||
| import org.springframework.security.core.context.SecurityContextHolder; | ||||
|  | ||||
| import java.util.Optional; | ||||
|  | ||||
| import static org.assertj.core.api.Assertions.assertThat; | ||||
|  | ||||
| public class MockSecurityContext { | ||||
|  | ||||
|     public static void givenLoginUserWithRole(final Role userRole) { | ||||
|         final String fakeUserName = userRole.name(); | ||||
|  | ||||
|         SecurityContext securityContext = SecurityContextHolder.createEmptyContext(); | ||||
|         securityContext.setAuthentication(new UsernamePasswordAuthenticationToken(fakeUserName, "dummy")); | ||||
|         SecurityContextHolder.setContext(securityContext); | ||||
|         Optional<String> login = SecurityUtils.getCurrentUserLogin(); | ||||
|  | ||||
|         assertThat(login).describedAs("precondition failed").contains(fakeUserName); | ||||
|     } | ||||
| } | ||||
| @@ -3,6 +3,7 @@ package org.hostsharing.hsadminng.service.dto; | ||||
| import com.fasterxml.jackson.core.JsonProcessingException; | ||||
| import com.fasterxml.jackson.databind.ObjectMapper; | ||||
| import org.hostsharing.hsadminng.security.SecurityUtils; | ||||
| import org.hostsharing.hsadminng.service.accessfilter.Role; | ||||
| import org.junit.Test; | ||||
| import org.junit.runner.RunWith; | ||||
| import org.springframework.beans.factory.annotation.Autowired; | ||||
| @@ -16,6 +17,7 @@ import java.io.IOException; | ||||
| import java.util.Optional; | ||||
|  | ||||
| import static org.assertj.core.api.Assertions.assertThat; | ||||
| import static org.hostsharing.hsadminng.service.accessfilter.MockSecurityContext.givenLoginUserWithRole; | ||||
| import static org.junit.Assert.assertEquals; | ||||
|  | ||||
| @JsonTest | ||||
| @@ -30,7 +32,7 @@ public class CustomerDTOUnitTest { | ||||
|  | ||||
|         // given | ||||
|         CustomerDTO given = createSomeCustomerDTO(); | ||||
|         givenLoginUserWithRole("ANY_CUSTOMER_USER"); | ||||
|         givenLoginUserWithRole(Role.ANY_CUSTOMER_USER); | ||||
|  | ||||
|         // when | ||||
|         String actual = objectMapper.writeValueAsString(given); | ||||
| @@ -49,7 +51,7 @@ public class CustomerDTOUnitTest { | ||||
|  | ||||
|         // given | ||||
|         CustomerDTO given = createSomeCustomerDTO(); | ||||
|         givenLoginUserWithRole("SUPPORTER"); | ||||
|         givenLoginUserWithRole(Role.SUPPORTER); | ||||
|  | ||||
|         // when | ||||
|         String actual = objectMapper.writeValueAsString(given); | ||||
| @@ -62,7 +64,7 @@ public class CustomerDTOUnitTest { | ||||
|     public void testDeserializeAsContractualCustomerContact() throws IOException { | ||||
|         // given | ||||
|         String json = "{\"id\":1234,\"reference\":10001,\"prefix\":\"abc\",\"name\":\"Mein Name\",\"contractualAddress\":\"Eine Adresse\",\"contractualSalutation\":\"Hallo\",\"billingAddress\":\"Noch eine Adresse\",\"billingSalutation\":\"Moin\",\"remark\":\"Eine Bemerkung\"}"; | ||||
|         givenLoginUserWithRole("CONTRACTUAL_CONTACT"); | ||||
|         givenLoginUserWithRole(Role.CONTRACTUAL_CONTACT); | ||||
|  | ||||
|         // when | ||||
|         CustomerDTO actual = objectMapper.readValue(json, CustomerDTO.class); | ||||
| @@ -120,12 +122,4 @@ public class CustomerDTOUnitTest { | ||||
|         given.setRemark("Eine Bemerkung"); | ||||
|         return given; | ||||
|     } | ||||
|  | ||||
|     private void givenLoginUserWithRole(String userName) { | ||||
|         SecurityContext securityContext = SecurityContextHolder.createEmptyContext(); | ||||
|         securityContext.setAuthentication(new UsernamePasswordAuthenticationToken(userName, userName)); | ||||
|         SecurityContextHolder.setContext(securityContext); | ||||
|         Optional<String> login = SecurityUtils.getCurrentUserLogin(); | ||||
|         assertThat(login).describedAs("precondition failed").contains(userName); | ||||
|     } | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user