From f4960f260e2e440d9b91547f28a05cd6ce15ca7f Mon Sep 17 00:00:00 2001 From: Michael Hoennig Date: Fri, 19 Apr 2019 07:18:20 +0200 Subject: [PATCH] moving the JSonSerializer to a separate package --- .../service/accessfilter/AccessFor.java | 16 ++++ .../JSonSerializerWithAccessFilter.java | 68 +++++++++++++++++ .../hsadminng/service/accessfilter/Role.java | 66 +++++++++++++++++ .../hsadminng/service/dto/CustomerDTO.java | 74 +------------------ .../service/dto/CustomerDTOUnitTest.java | 1 - 5 files changed, 152 insertions(+), 73 deletions(-) create mode 100644 src/main/java/org/hostsharing/hsadminng/service/accessfilter/AccessFor.java create mode 100644 src/main/java/org/hostsharing/hsadminng/service/accessfilter/JSonSerializerWithAccessFilter.java create mode 100644 src/main/java/org/hostsharing/hsadminng/service/accessfilter/Role.java diff --git a/src/main/java/org/hostsharing/hsadminng/service/accessfilter/AccessFor.java b/src/main/java/org/hostsharing/hsadminng/service/accessfilter/AccessFor.java new file mode 100644 index 00000000..d25b5c87 --- /dev/null +++ b/src/main/java/org/hostsharing/hsadminng/service/accessfilter/AccessFor.java @@ -0,0 +1,16 @@ +package org.hostsharing.hsadminng.service.accessfilter; + + +import java.lang.annotation.*; + +@Target({ElementType.FIELD, ElementType.TYPE_USE}) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface AccessFor { + Role[] init() default Role.NOBODY; + + Role[] update() default Role.NOBODY; + + Role[] read() default Role.NOBODY; +} + diff --git a/src/main/java/org/hostsharing/hsadminng/service/accessfilter/JSonSerializerWithAccessFilter.java b/src/main/java/org/hostsharing/hsadminng/service/accessfilter/JSonSerializerWithAccessFilter.java new file mode 100644 index 00000000..76a4734b --- /dev/null +++ b/src/main/java/org/hostsharing/hsadminng/service/accessfilter/JSonSerializerWithAccessFilter.java @@ -0,0 +1,68 @@ +package org.hostsharing.hsadminng.service.accessfilter; + + +import com.fasterxml.jackson.core.JsonGenerator; +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; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +@JsonComponent +public class JSonSerializerWithAccessFilter extends JsonSerializer { + + @Override + public void serialize(Object dto, JsonGenerator jsonGenerator, + SerializerProvider serializerProvider) throws IOException { + + jsonGenerator.writeStartObject(); + for (Field prop : CustomerDTO.class.getDeclaredFields()) { + toJSon(dto, jsonGenerator, prop); + } + + jsonGenerator.writeEndObject(); + } + + private void toJSon(Object dto, JsonGenerator jsonGenerator, Field prop) throws IOException { + if (getLoginUserRole().isAllowedToRead(prop)) { + final String fieldName = prop.getName(); + 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())) { + jsonGenerator.writeNumberField(fieldName, (long) get(dto, prop)); + } else if (String.class.isAssignableFrom(prop.getType())) { + jsonGenerator.writeStringField(fieldName, (String) get(dto, prop)); + } else { + throw new NotImplementedException("property type not yet implemented" + prop); + } + } + } + + private Object get(Object dto, Field field) { + try { + field.setAccessible(true); + return field.get(dto); + } catch (IllegalAccessException e) { + throw new RuntimeException(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); + } + } + +} diff --git a/src/main/java/org/hostsharing/hsadminng/service/accessfilter/Role.java b/src/main/java/org/hostsharing/hsadminng/service/accessfilter/Role.java new file mode 100644 index 00000000..aaf1f473 --- /dev/null +++ b/src/main/java/org/hostsharing/hsadminng/service/accessfilter/Role.java @@ -0,0 +1,66 @@ +package org.hostsharing.hsadminng.service.accessfilter; + +import org.hostsharing.hsadminng.security.SecurityUtils; + +import java.lang.reflect.Field; + +public enum Role { + NOBODY(0), HOSTMASTER(1), ADMIN(2), SUPPORTER(3), + ANY_CUSTOMER_CONTACT(20), CONTRACTUAL_CONTACT(21), FINANCIAL_CONTACT(22), TECHNICAL_CONTACT(22), + ANY_CUSTOMER_USER(80), + ANYBODY(99); + + private final int level; + + Role(final int level) { + this.level = level; + } + + boolean covers(final Role role) { + return this == role || this.level < role.level; + } + + public boolean isAllowedToInit(Field field) { + + final AccessFor accessFor = field.getAnnotation(AccessFor.class); + if (accessFor == null) { + return false; + } + + return isRoleCovered(accessFor.init()); + } + + public boolean isAllowedToUpdate(Field field) { + + final Role loginUserRole = SecurityUtils.getCurrentUserLogin().map(u -> Role.valueOf(u.toUpperCase())).orElse(Role.ANYBODY); + + final AccessFor accessFor = field.getAnnotation(AccessFor.class); + if (accessFor == null) { + return false; + } + + return isRoleCovered(accessFor.update()); + } + + public boolean isAllowedToRead(Field field) { + + final Role loginUserRole = SecurityUtils.getCurrentUserLogin().map(u -> Role.valueOf(u.toUpperCase())).orElse(Role.ANYBODY); + + final AccessFor accessFor = field.getAnnotation(AccessFor.class); + if (accessFor == null) { + return false; + } + + return isRoleCovered(accessFor.read()); + } + + private boolean isRoleCovered(Role[] requiredRoles) { + for (Role accessAllowedForRole : requiredRoles) { + if (this.covers(accessAllowedForRole)) { + return true; + } + } + return false; + } + +} diff --git a/src/main/java/org/hostsharing/hsadminng/service/dto/CustomerDTO.java b/src/main/java/org/hostsharing/hsadminng/service/dto/CustomerDTO.java index de2a6ba3..e7ba3fe5 100644 --- a/src/main/java/org/hostsharing/hsadminng/service/dto/CustomerDTO.java +++ b/src/main/java/org/hostsharing/hsadminng/service/dto/CustomerDTO.java @@ -11,6 +11,8 @@ import com.fasterxml.jackson.databind.node.IntNode; import com.fasterxml.jackson.databind.node.TextNode; import org.apache.commons.lang3.NotImplementedException; import org.hostsharing.hsadminng.security.SecurityUtils; +import org.hostsharing.hsadminng.service.accessfilter.AccessFor; +import org.hostsharing.hsadminng.service.accessfilter.Role; import org.springframework.boot.jackson.JsonComponent; import javax.validation.constraints.*; @@ -254,75 +256,3 @@ public class CustomerDTO implements Serializable { } } -enum Role { - NOBODY(0), HOSTMASTER(1), ADMIN(2), SUPPORTER(3), - ANY_CUSTOMER_CONTACT(20), CONTRACTUAL_CONTACT(21), FINANCIAL_CONTACT(22), TECHNICAL_CONTACT(22), - ANY_CUSTOMER_USER(80), - ANYBODY(99); - - private final int level; - - Role(final int level) { - this.level = level; - } - - boolean covers(final Role role) { - return this == role || this.level < role.level; - } - - public boolean isAllowedToInit(Field field) { - - final AccessFor accessFor = field.getAnnotation(AccessFor.class); - if (accessFor == null) { - return false; - } - - return isRoleCovered(accessFor.init()); - } - - public boolean isAllowedToUpdate(Field field) { - - final Role loginUserRole = SecurityUtils.getCurrentUserLogin().map(u -> Role.valueOf(u.toUpperCase())).orElse(Role.ANYBODY); - - final AccessFor accessFor = field.getAnnotation(AccessFor.class); - if (accessFor == null) { - return false; - } - - return isRoleCovered(accessFor.update()); - } - - public boolean isAllowedToRead(Field field) { - - final Role loginUserRole = SecurityUtils.getCurrentUserLogin().map(u -> Role.valueOf(u.toUpperCase())).orElse(Role.ANYBODY); - - final AccessFor accessFor = field.getAnnotation(AccessFor.class); - if (accessFor == null) { - return false; - } - - return isRoleCovered(accessFor.read()); - } - - private boolean isRoleCovered(Role[] requiredRoles) { - for (Role accessAllowedForRole : requiredRoles) { - if (this.covers(accessAllowedForRole)) { - return true; - } - } - return false; - } - -} - -@Target({ElementType.FIELD, ElementType.TYPE_USE}) -@Retention(RetentionPolicy.RUNTIME) -@Documented -@interface AccessFor { - Role[] init() default Role.NOBODY; - - Role[] update() default Role.NOBODY; - - Role[] read() default Role.NOBODY; -} - diff --git a/src/test/java/org/hostsharing/hsadminng/service/dto/CustomerDTOUnitTest.java b/src/test/java/org/hostsharing/hsadminng/service/dto/CustomerDTOUnitTest.java index 1ad1cc5d..6ef88849 100644 --- a/src/test/java/org/hostsharing/hsadminng/service/dto/CustomerDTOUnitTest.java +++ b/src/test/java/org/hostsharing/hsadminng/service/dto/CustomerDTOUnitTest.java @@ -22,7 +22,6 @@ import static org.junit.Assert.assertEquals; @RunWith(SpringRunner.class) public class CustomerDTOUnitTest { - @Autowired private ObjectMapper objectMapper;