From 0d202b55744f0a8338672d5a2fe80a22616cec41 Mon Sep 17 00:00:00 2001 From: kirillius Date: Thu, 8 Jan 2026 17:43:20 +0300 Subject: [PATCH] =?UTF-8?q?=D0=A3=D0=B1=D1=80=D0=B0=D0=BB=20=D0=B7=D0=B0?= =?UTF-8?q?=D0=B2=D0=B8=D1=81=D0=B8=D0=BC=D0=BE=D1=81=D1=82=D1=8C=20db=20?= =?UTF-8?q?=D0=BE=D1=82=20core.=20=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=20=D0=B8=D0=BD=D0=B6=D0=B5=D0=BA=D1=86=D0=B8=D1=8E=20con?= =?UTF-8?q?text=20=D0=B2=20Entity?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ru/kirillius/XCP/Commons/Context.java | 4 +-- .../XCP/Security/SecurityManager.java | 5 ++++ database/pom.xml | 6 ----- .../XCP/Persistence/AbstractRepository.java | 6 ++++- .../Persistence/ContextReferencedEntity.java | 8 ++++++ .../Repositories/UserRepositoryImpl.java | 21 ++++++++++------ .../Persistence/RepositoryServiceImpl.java | 25 +++++++++++++++++++ .../XCP/Persistence/TestEnvironment.java | 10 +++++++- .../XCP/Persistence/TestHashUtil.java | 16 ++++++++++++ 9 files changed, 83 insertions(+), 18 deletions(-) create mode 100644 api/src/main/java/ru/kirillius/XCP/Security/SecurityManager.java create mode 100644 database/src/main/java/ru/kirillius/XCP/Persistence/ContextReferencedEntity.java create mode 100644 database/src/test/java/ru/kirillius/XCP/Persistence/TestHashUtil.java diff --git a/api/src/main/java/ru/kirillius/XCP/Commons/Context.java b/api/src/main/java/ru/kirillius/XCP/Commons/Context.java index 2c011bd..af8995d 100644 --- a/api/src/main/java/ru/kirillius/XCP/Commons/Context.java +++ b/api/src/main/java/ru/kirillius/XCP/Commons/Context.java @@ -1,6 +1,6 @@ package ru.kirillius.XCP.Commons; -import ru.kirillius.XCP.Security.HashUtility; +import ru.kirillius.XCP.Security.SecurityManager; public interface Context { Config getConfig(); @@ -11,5 +11,5 @@ public interface Context { void shutdown(); - HashUtility getHashUtility(); + SecurityManager getSecurityManager(); } diff --git a/api/src/main/java/ru/kirillius/XCP/Security/SecurityManager.java b/api/src/main/java/ru/kirillius/XCP/Security/SecurityManager.java new file mode 100644 index 0000000..61fb390 --- /dev/null +++ b/api/src/main/java/ru/kirillius/XCP/Security/SecurityManager.java @@ -0,0 +1,5 @@ +package ru.kirillius.XCP.Security; + +public interface SecurityManager { + HashUtility getHashUtility(); +} diff --git a/database/pom.xml b/database/pom.xml index 3ca3f76..e33ac8a 100644 --- a/database/pom.xml +++ b/database/pom.xml @@ -41,12 +41,6 @@ 1.0.0.0 compile - - ru.kirillius - core - 1.0.0.0 - compile - \ No newline at end of file diff --git a/database/src/main/java/ru/kirillius/XCP/Persistence/AbstractRepository.java b/database/src/main/java/ru/kirillius/XCP/Persistence/AbstractRepository.java index 6404857..252dce5 100644 --- a/database/src/main/java/ru/kirillius/XCP/Persistence/AbstractRepository.java +++ b/database/src/main/java/ru/kirillius/XCP/Persistence/AbstractRepository.java @@ -37,7 +37,11 @@ public abstract class AbstractRepository implements public E create() { try { var constructor = entityImplementationClass.getConstructor(); - return constructor.newInstance(); + var instance= constructor.newInstance(); + if(instance instanceof ContextReferencedEntity referencedEntity) { + referencedEntity.setContext(repositoryService.getContext()); + } + return instance; } catch (NoSuchMethodException | InvocationTargetException | InstantiationException | IllegalAccessException e) { throw new RuntimeException("Unable to instantiate entity", e); diff --git a/database/src/main/java/ru/kirillius/XCP/Persistence/ContextReferencedEntity.java b/database/src/main/java/ru/kirillius/XCP/Persistence/ContextReferencedEntity.java new file mode 100644 index 0000000..4d201e8 --- /dev/null +++ b/database/src/main/java/ru/kirillius/XCP/Persistence/ContextReferencedEntity.java @@ -0,0 +1,8 @@ +package ru.kirillius.XCP.Persistence; + +import ru.kirillius.XCP.Commons.Context; + +public interface ContextReferencedEntity { + void setContext(Context context); + Context getContext(); +} diff --git a/database/src/main/java/ru/kirillius/XCP/Persistence/Repositories/UserRepositoryImpl.java b/database/src/main/java/ru/kirillius/XCP/Persistence/Repositories/UserRepositoryImpl.java index 1f2cb19..c415984 100644 --- a/database/src/main/java/ru/kirillius/XCP/Persistence/Repositories/UserRepositoryImpl.java +++ b/database/src/main/java/ru/kirillius/XCP/Persistence/Repositories/UserRepositoryImpl.java @@ -1,14 +1,16 @@ package ru.kirillius.XCP.Persistence.Repositories; +import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; import jakarta.persistence.*; import lombok.*; import org.hibernate.annotations.UuidGenerator; +import ru.kirillius.XCP.Commons.Context; import ru.kirillius.XCP.Persistence.AbstractRepository; +import ru.kirillius.XCP.Persistence.ContextReferencedEntity; import ru.kirillius.XCP.Persistence.Entities.User; import ru.kirillius.XCP.Persistence.EntityImplementation; import ru.kirillius.XCP.Persistence.RepositoryServiceImpl; -import ru.kirillius.XCP.Security.Argon2HashUtility; import ru.kirillius.XCP.Security.UserRole; import ru.kirillius.XCP.Serialization.SerializationUtils; import tools.jackson.databind.node.ObjectNode; @@ -24,8 +26,6 @@ public class UserRepositoryImpl extends AbstractRepository implements User super(repositoryService); } - - @Override public User getByLogin(String login) { try (var request = buildQueryParametrized("WHERE login = ?1", login)) { @@ -42,7 +42,13 @@ public class UserRepositoryImpl extends AbstractRepository implements User @NoArgsConstructor @Getter @Setter - public static class UserEntity implements User { + public static class UserEntity implements User, ContextReferencedEntity { + @Transient + @JsonIgnore + @Getter + @Setter + private Context context; + @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @JsonProperty @@ -68,7 +74,7 @@ public class UserRepositoryImpl extends AbstractRepository implements User @Column(nullable = false) @JsonProperty @Enumerated(EnumType.STRING) - private UserRole role=UserRole.User; + private UserRole role = UserRole.User; @Column(name = "custom_values", nullable = false) @Getter @@ -76,15 +82,14 @@ public class UserRepositoryImpl extends AbstractRepository implements User @JsonProperty private ObjectNode values = SerializationUtils.EmptyObject(); - @Override public void setPassword(String password) { - passwordHash = Argon2HashUtility.getInstance().hash(password); + passwordHash = context.getSecurityManager().getHashUtility().hash(password); } @Override public boolean verifyPassword(String password) { - return Argon2HashUtility.getInstance().validate(password, passwordHash); + return context.getSecurityManager().getHashUtility().validate(password, passwordHash); } @Override diff --git a/database/src/main/java/ru/kirillius/XCP/Persistence/RepositoryServiceImpl.java b/database/src/main/java/ru/kirillius/XCP/Persistence/RepositoryServiceImpl.java index 29a6826..4ecc39b 100644 --- a/database/src/main/java/ru/kirillius/XCP/Persistence/RepositoryServiceImpl.java +++ b/database/src/main/java/ru/kirillius/XCP/Persistence/RepositoryServiceImpl.java @@ -1,9 +1,11 @@ package ru.kirillius.XCP.Persistence; import lombok.Getter; +import org.hibernate.Interceptor; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.cfg.Configuration; +import org.hibernate.type.Type; import ru.kirillius.XCP.Commons.Context; import tools.jackson.databind.ObjectMapper; import tools.jackson.databind.json.JsonMapper; @@ -26,6 +28,7 @@ public final class RepositoryServiceImpl implements RepositoryService { private final Map>, Class>> repositoryBaseBindings = new ConcurrentHashMap<>(); private final Map, Class>> entityBindings = new ConcurrentHashMap<>(); private final Collection>> managedRepositoryClasses; + @Getter private Context context; public RepositoryServiceImpl(DatabaseConfiguration databaseConfiguration, Collection>> repositoryImplClasses) { @@ -102,9 +105,28 @@ public final class RepositoryServiceImpl implements RepositoryService { entityBindings.put(entityClass, baseClass); }); mapper = JsonMapper.builder().addModule(new PersistenceSerializationModule(this)).build(); + this.configuration.setInterceptor(new EntityInterceptor(context)); sessionFactory = this.configuration.buildSessionFactory(); } + public static class EntityInterceptor implements Interceptor { + private final Context context; + + private EntityInterceptor(Context context) { + this.context = context; + } + + @Override + public boolean onLoad(Object entity, Object id, Object[] state, String[] propertyNames, Type[] types) { + if (entity instanceof ContextReferencedEntity referencedEntity) { + if (referencedEntity.getContext() == null) { + referencedEntity.setContext(context); + } + } + return false; + } + } + @Override public Repository getRepositoryForEntity(Class entityType) { //noinspection unchecked @@ -119,6 +141,7 @@ public final class RepositoryServiceImpl implements RepositoryService { /** * Returns entity base interface Class from Class + * * @param entityClass * @return Class */ @@ -138,6 +161,7 @@ public final class RepositoryServiceImpl implements RepositoryService { /** * Returns repository base interface type Class from Class + * * @param repositoryClass * @return Class */ @@ -157,6 +181,7 @@ public final class RepositoryServiceImpl implements RepositoryService { /** * Returns Entity implementation class that implements E from Class> + * * @param repositoryImplClass * @return Class */ diff --git a/database/src/test/java/ru/kirillius/XCP/Persistence/TestEnvironment.java b/database/src/test/java/ru/kirillius/XCP/Persistence/TestEnvironment.java index 62b554d..c71db78 100644 --- a/database/src/test/java/ru/kirillius/XCP/Persistence/TestEnvironment.java +++ b/database/src/test/java/ru/kirillius/XCP/Persistence/TestEnvironment.java @@ -1,15 +1,23 @@ package ru.kirillius.XCP.Persistence; import ru.kirillius.XCP.Commons.Context; +import ru.kirillius.XCP.Security.SecurityManager; import java.util.Collection; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; public class TestEnvironment { public static RepositoryServiceImpl instantiateTestService(Collection>> classes) { var service = new RepositoryServiceImpl(new H2InMemoryConfiguration(), classes); - service.initialize(mock(Context.class)); + var context = mock(Context.class); + var securityManager = mock(SecurityManager.class); + + when(context.getSecurityManager()).thenReturn(securityManager); + when(securityManager.getHashUtility()).thenReturn(new TestHashUtil()); + + service.initialize(context); return service; } } diff --git a/database/src/test/java/ru/kirillius/XCP/Persistence/TestHashUtil.java b/database/src/test/java/ru/kirillius/XCP/Persistence/TestHashUtil.java new file mode 100644 index 0000000..c9bdf37 --- /dev/null +++ b/database/src/test/java/ru/kirillius/XCP/Persistence/TestHashUtil.java @@ -0,0 +1,16 @@ +package ru.kirillius.XCP.Persistence; + +import ru.kirillius.XCP.Security.HashUtility; + +public class TestHashUtil implements HashUtility { + + @Override + public String hash(String password) { + return "hashed(" + password.hashCode() + ")"; + } + + @Override + public boolean validate(String password, String hash) { + return HashUtility.super.validate(password, hash); + } +}