move annotation service to cite repo
This commit is contained in:
parent
ef5134c629
commit
0e8398a453
|
@ -1,38 +0,0 @@
|
||||||
####################################### Build stage #######################################
|
|
||||||
FROM maven:3.9-eclipse-temurin-21-alpine AS build-stage
|
|
||||||
|
|
||||||
ARG MAVEN_ACCOUNT_USR
|
|
||||||
ARG MAVEN_ACCOUNT_PSW
|
|
||||||
ARG REVISION
|
|
||||||
ARG PROFILE
|
|
||||||
ENV server_username=$MAVEN_ACCOUNT_USR
|
|
||||||
ENV server_password=$MAVEN_ACCOUNT_PSW
|
|
||||||
ARG CITE_MAVEN_REPO_URL
|
|
||||||
|
|
||||||
COPY pom.xml /build/
|
|
||||||
COPY annotation /build/annotation/
|
|
||||||
COPY annotation-web /build/annotation-web/
|
|
||||||
COPY settings.xml /root/.m2/settings.xml
|
|
||||||
RUN rm -f /build/annotation-web/src/main/resources/config/app.env
|
|
||||||
RUN rm -f /build/annotation-web/src/main/resources/config/*-devel.yml
|
|
||||||
RUN rm -f /build/annotation-web/src/main/resources/logging/*.xml
|
|
||||||
RUN rm -f /build/annotation-web/src/main/resources/certificates/*.crt
|
|
||||||
|
|
||||||
WORKDIR /build/
|
|
||||||
|
|
||||||
RUN mvn -Drevision=${REVISION} -DciteMavenRepoUrl=${CITE_MAVEN_REPO_URL} -P${PROFILE} clean
|
|
||||||
RUN mvn -Drevision=${REVISION} -DciteMavenRepoUrl=${CITE_MAVEN_REPO_URL} -P${PROFILE} install
|
|
||||||
# Build project
|
|
||||||
RUN mvn -Drevision=${REVISION} -DciteMavenRepoUrl=${CITE_MAVEN_REPO_URL} -P${PROFILE} package
|
|
||||||
|
|
||||||
######################################## Run Stage ########################################
|
|
||||||
FROM eclipse-temurin:21-jre-ubi9-minimal
|
|
||||||
|
|
||||||
ARG PROFILE
|
|
||||||
ARG REVISION
|
|
||||||
ENV SERVER_PORT=8080
|
|
||||||
EXPOSE ${SERVER_PORT}
|
|
||||||
|
|
||||||
COPY --from=build-stage /build/annotation-web/target/annotation-web-${REVISION}.jar /app/annotation-web.jar
|
|
||||||
|
|
||||||
ENTRYPOINT ["java","-Dspring.config.additional-location=file:/config/","-Dspring.profiles.active=${PROFILE}","-Djava.security.egd=file:/dev/./urandom","-jar","/app/annotation-web.jar"]
|
|
|
@ -1,30 +0,0 @@
|
||||||
####################################### Build stage #######################################
|
|
||||||
FROM maven:3.9-eclipse-temurin-21-alpine
|
|
||||||
|
|
||||||
ARG MAVEN_ACCOUNT_USR
|
|
||||||
ARG MAVEN_ACCOUNT_PSW
|
|
||||||
ARG REVISION
|
|
||||||
ARG PROFILE
|
|
||||||
ARG ORACLE_URL
|
|
||||||
ARG ORACLE_TOKEN
|
|
||||||
ENV server_username=$MAVEN_ACCOUNT_USR
|
|
||||||
ENV server_password=$MAVEN_ACCOUNT_PSW
|
|
||||||
ARG CITE_MAVEN_REPO_URL
|
|
||||||
|
|
||||||
COPY pom.xml /build/
|
|
||||||
COPY annotation /build/annotation/
|
|
||||||
COPY annotation-web /build/annotation-web/
|
|
||||||
COPY settings.xml /root/.m2/settings.xml
|
|
||||||
RUN rm -f /build/annotation-web/src/main/resources/config/app.env
|
|
||||||
RUN rm -f /build/annotation-web/src/main/resources/config/*-devel.yml
|
|
||||||
RUN rm -f /build/annotation-web/src/main/resources/logging/*.xml
|
|
||||||
RUN rm -f /build/annotation-web/src/main/resources/certificates/*.crt
|
|
||||||
|
|
||||||
COPY oracle.local.cite.gr.crt $JAVA_HOME/conf/security
|
|
||||||
RUN cd "$JAVA_HOME"/conf/security && keytool -cacerts -storepass changeit -noprompt -trustcacerts -importcert -alias oraclecert -file oracle.local.cite.gr.crt
|
|
||||||
|
|
||||||
WORKDIR /build/
|
|
||||||
RUN mvn -Drevision=${REVISION} -DciteMavenRepoUrl=${CITE_MAVEN_REPO_URL} -P${PROFILE} clean
|
|
||||||
RUN mvn -Drevision=${REVISION} -DciteMavenRepoUrl=${CITE_MAVEN_REPO_URL} -P${PROFILE} install
|
|
||||||
RUN mvn -Drevision=${REVISION} -DciteMavenRepoUrl=${CITE_MAVEN_REPO_URL} -P${PROFILE} package
|
|
||||||
RUN mvn sonar:sonar -Drevision=${REVISION} -DciteMavenRepoUrl=${CITE_MAVEN_REPO_URL} -P${PROFILE} -Dsonar.projectKey=OpenDMP:annotation-api -Dsonar.login=${ORACLE_TOKEN} -Dsonar.host.url=${ORACLE_URL} -Dsonar.projectName='OpenDMP Annotation API'
|
|
|
@ -1,33 +0,0 @@
|
||||||
HELP.md
|
|
||||||
target/
|
|
||||||
!.mvn/wrapper/maven-wrapper.jar
|
|
||||||
!**/src/main/**/target/
|
|
||||||
!**/src/test/**/target/
|
|
||||||
|
|
||||||
### STS ###
|
|
||||||
.apt_generated
|
|
||||||
.classpath
|
|
||||||
.factorypath
|
|
||||||
.project
|
|
||||||
.settings
|
|
||||||
.springBeans
|
|
||||||
.sts4-cache
|
|
||||||
|
|
||||||
### IntelliJ IDEA ###
|
|
||||||
.idea
|
|
||||||
*.iws
|
|
||||||
*.iml
|
|
||||||
*.ipr
|
|
||||||
|
|
||||||
### NetBeans ###
|
|
||||||
/nbproject/private/
|
|
||||||
/nbbuild/
|
|
||||||
/dist/
|
|
||||||
/nbdist/
|
|
||||||
/.nb-gradle/
|
|
||||||
build/
|
|
||||||
!**/src/main/**/build/
|
|
||||||
!**/src/test/**/build/
|
|
||||||
|
|
||||||
### VS Code ###
|
|
||||||
.vscode/
|
|
|
@ -1,91 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
|
||||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
||||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
|
||||||
<modelVersion>4.0.0</modelVersion>
|
|
||||||
|
|
||||||
<parent>
|
|
||||||
<groupId>gr.cite</groupId>
|
|
||||||
<artifactId>annotation-service-parent</artifactId>
|
|
||||||
<version>${revision}</version>
|
|
||||||
<relativePath>../pom.xml</relativePath>
|
|
||||||
</parent>
|
|
||||||
|
|
||||||
<artifactId>annotation-web</artifactId>
|
|
||||||
<version>${revision}</version>
|
|
||||||
<packaging>jar</packaging>
|
|
||||||
|
|
||||||
<properties>
|
|
||||||
<maven.compiler.release>21</maven.compiler.release>
|
|
||||||
<maven.compiler.source>21</maven.compiler.source>
|
|
||||||
<maven.compiler.target>21</maven.compiler.target>
|
|
||||||
<revision>1.0.0-SNAPSHOT</revision>
|
|
||||||
</properties>
|
|
||||||
|
|
||||||
<dependencies>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.springframework.boot</groupId>
|
|
||||||
<artifactId>spring-boot-starter-web</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.springframework.boot</groupId>
|
|
||||||
<artifactId>spring-boot-starter-webflux</artifactId>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.springframework.boot</groupId>
|
|
||||||
<artifactId>spring-boot-starter-validation</artifactId>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.postgresql</groupId>
|
|
||||||
<artifactId>postgresql</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.hibernate.orm</groupId>
|
|
||||||
<artifactId>hibernate-core</artifactId>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.springframework.boot</groupId>
|
|
||||||
<artifactId>spring-boot-starter-tomcat</artifactId>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>gr.cite</groupId>
|
|
||||||
<artifactId>annotation</artifactId>
|
|
||||||
<version>${revision}</version>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>gr.cite</groupId>
|
|
||||||
<artifactId>oidc-authz</artifactId>
|
|
||||||
<version>2.1.0</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>gr.cite</groupId>
|
|
||||||
<artifactId>cache</artifactId>
|
|
||||||
<version>2.2.0</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>gr.cite</groupId>
|
|
||||||
<artifactId>exceptions-web</artifactId>
|
|
||||||
<version>2.1.0</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>gr.cite</groupId>
|
|
||||||
<artifactId>cors-web</artifactId>
|
|
||||||
<version>2.1.0</version>
|
|
||||||
</dependency>
|
|
||||||
</dependencies>
|
|
||||||
|
|
||||||
<build>
|
|
||||||
<plugins>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.springframework.boot</groupId>
|
|
||||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
|
||||||
</plugin>
|
|
||||||
</plugins>
|
|
||||||
</build>
|
|
||||||
|
|
||||||
</project>
|
|
|
@ -1,26 +0,0 @@
|
||||||
package gr.cite.annotation.web;
|
|
||||||
|
|
||||||
import org.springframework.boot.SpringApplication;
|
|
||||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
|
||||||
import org.springframework.boot.autoconfigure.domain.EntityScan;
|
|
||||||
import org.springframework.scheduling.annotation.EnableAsync;
|
|
||||||
|
|
||||||
@SpringBootApplication(
|
|
||||||
scanBasePackages = {
|
|
||||||
"gr.cite.annotation.*",
|
|
||||||
"gr.cite",
|
|
||||||
"gr.cite.queueoutbox",
|
|
||||||
"gr.cite.queueinbox",
|
|
||||||
"gr.cite.annotation.integrationevent",
|
|
||||||
"gr.cite.tools",
|
|
||||||
"gr.cite.commons"})
|
|
||||||
@EntityScan({
|
|
||||||
"gr.cite.annotation.data"})
|
|
||||||
@EnableAsync
|
|
||||||
public class AnnotationApplication {
|
|
||||||
|
|
||||||
public static void main(String[] args) {
|
|
||||||
SpringApplication.run(AnnotationApplication.class, args);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,40 +0,0 @@
|
||||||
package gr.cite.annotation.web;
|
|
||||||
|
|
||||||
import gr.cite.annotation.web.scope.tenant.TenantInterceptor;
|
|
||||||
import gr.cite.annotation.web.scope.tenant.TenantScopeClaimInterceptor;
|
|
||||||
import gr.cite.annotation.web.scope.tenant.TenantScopeHeaderInterceptor;
|
|
||||||
import gr.cite.annotation.web.scope.user.UserInterceptor;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.context.annotation.Configuration;
|
|
||||||
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
|
|
||||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
|
||||||
|
|
||||||
@Configuration
|
|
||||||
public class WebConfiguration implements WebMvcConfigurer {
|
|
||||||
private final TenantInterceptor tenantInterceptor;
|
|
||||||
private final TenantScopeHeaderInterceptor scopeHeaderInterceptor;
|
|
||||||
private final TenantScopeClaimInterceptor scopeClaimInterceptor;
|
|
||||||
private final UserInterceptor userInterceptor;
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
public WebConfiguration(
|
|
||||||
TenantInterceptor tenantInterceptor,
|
|
||||||
TenantScopeHeaderInterceptor scopeHeaderInterceptor,
|
|
||||||
TenantScopeClaimInterceptor scopeClaimInterceptor,
|
|
||||||
UserInterceptor userInterceptor
|
|
||||||
) {
|
|
||||||
this.tenantInterceptor = tenantInterceptor;
|
|
||||||
this.scopeHeaderInterceptor = scopeHeaderInterceptor;
|
|
||||||
this.scopeClaimInterceptor = scopeClaimInterceptor;
|
|
||||||
this.userInterceptor = userInterceptor;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void addInterceptors(InterceptorRegistry registry) {
|
|
||||||
int order = 1;
|
|
||||||
registry.addWebRequestInterceptor(scopeHeaderInterceptor).order(order++);
|
|
||||||
registry.addWebRequestInterceptor(scopeClaimInterceptor).order(order++);
|
|
||||||
registry.addWebRequestInterceptor(userInterceptor).order(order++);
|
|
||||||
registry.addWebRequestInterceptor(tenantInterceptor).order(order++);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,56 +0,0 @@
|
||||||
package gr.cite.annotation.web.authorization;
|
|
||||||
|
|
||||||
import gr.cite.annotation.authorization.AffiliatedAuthorizationRequirement;
|
|
||||||
import gr.cite.annotation.authorization.AffiliatedResource;
|
|
||||||
import gr.cite.commons.web.authz.handler.AuthorizationHandler;
|
|
||||||
import gr.cite.commons.web.authz.handler.AuthorizationHandlerContext;
|
|
||||||
import gr.cite.commons.web.authz.policy.AuthorizationRequirement;
|
|
||||||
import gr.cite.commons.web.oidc.principal.MyPrincipal;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
|
|
||||||
@Component("affiliatedAuthorizationHandler")
|
|
||||||
public class AffiliatedAuthorizationHandler extends AuthorizationHandler<AffiliatedAuthorizationRequirement> {
|
|
||||||
|
|
||||||
private final CustomPermissionAttributesConfiguration myConfiguration;
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
public AffiliatedAuthorizationHandler(CustomPermissionAttributesConfiguration myConfiguration) {
|
|
||||||
this.myConfiguration = myConfiguration;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int handleRequirement(AuthorizationHandlerContext context, Object resource, AuthorizationRequirement requirement) {
|
|
||||||
AffiliatedAuthorizationRequirement req = (AffiliatedAuthorizationRequirement) requirement;
|
|
||||||
if (req.getRequiredPermissions() == null)
|
|
||||||
return ACCESS_NOT_DETERMINED;
|
|
||||||
|
|
||||||
AffiliatedResource rs = (AffiliatedResource) resource;
|
|
||||||
|
|
||||||
boolean isAuthenticated = ((MyPrincipal) context.getPrincipal()).isAuthenticated();
|
|
||||||
if (!isAuthenticated)
|
|
||||||
return ACCESS_NOT_DETERMINED;
|
|
||||||
|
|
||||||
if (myConfiguration.getMyPolicies() == null)
|
|
||||||
return ACCESS_NOT_DETERMINED;
|
|
||||||
|
|
||||||
int hits = 0;
|
|
||||||
Boolean entityAffiliated = rs != null && rs.getAffiliated() != null ? rs.getAffiliated() : null;
|
|
||||||
|
|
||||||
for (String permission : req.getRequiredPermissions()) {
|
|
||||||
CustomPermissionAttributesProperties.MyPermission policy = myConfiguration.getMyPolicies().get(permission);
|
|
||||||
boolean hasPermission = policy != null && policy.getEntityAffiliated() != null && policy.getEntityAffiliated() && entityAffiliated != null && entityAffiliated;
|
|
||||||
if (hasPermission) hits += 1;
|
|
||||||
}
|
|
||||||
if ((req.getMatchAll() && req.getRequiredPermissions().size() == hits) || (!req.getMatchAll() && hits > 0))
|
|
||||||
return ACCESS_GRANTED;
|
|
||||||
|
|
||||||
return ACCESS_NOT_DETERMINED;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Class<? extends AuthorizationRequirement> supporting() {
|
|
||||||
return AffiliatedAuthorizationRequirement.class;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,24 +0,0 @@
|
||||||
package gr.cite.annotation.web.authorization;
|
|
||||||
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
|
||||||
import org.springframework.context.annotation.Configuration;
|
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
|
|
||||||
@Configuration
|
|
||||||
@EnableConfigurationProperties(CustomPermissionAttributesProperties.class)
|
|
||||||
public class CustomPermissionAttributesConfiguration {
|
|
||||||
|
|
||||||
private final CustomPermissionAttributesProperties properties;
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
public CustomPermissionAttributesConfiguration(CustomPermissionAttributesProperties properties) {
|
|
||||||
this.properties = properties;
|
|
||||||
}
|
|
||||||
|
|
||||||
public HashMap<String, CustomPermissionAttributesProperties.MyPermission> getMyPolicies() {
|
|
||||||
return properties.getPolicies();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,38 +0,0 @@
|
||||||
package gr.cite.annotation.web.authorization;
|
|
||||||
|
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
|
||||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
|
||||||
import org.springframework.boot.context.properties.bind.ConstructorBinding;
|
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
|
|
||||||
@ConfigurationProperties(prefix = "permissions")
|
|
||||||
@ConditionalOnProperty(prefix = "permissions", name = "enabled", havingValue = "true")
|
|
||||||
public class CustomPermissionAttributesProperties {
|
|
||||||
|
|
||||||
private final HashMap<String, MyPermission> policies;
|
|
||||||
|
|
||||||
@ConstructorBinding
|
|
||||||
public CustomPermissionAttributesProperties(HashMap<String, MyPermission> policies) {
|
|
||||||
this.policies = policies;
|
|
||||||
}
|
|
||||||
|
|
||||||
public HashMap<String, MyPermission> getPolicies() {
|
|
||||||
return policies;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class MyPermission {
|
|
||||||
|
|
||||||
private final Boolean entityAffiliated;
|
|
||||||
|
|
||||||
@ConstructorBinding
|
|
||||||
public MyPermission(Boolean entityAffiliated) {
|
|
||||||
this.entityAffiliated = entityAffiliated;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Boolean getEntityAffiliated() {
|
|
||||||
return entityAffiliated;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,44 +0,0 @@
|
||||||
package gr.cite.annotation.web.authorization;
|
|
||||||
|
|
||||||
import gr.cite.commons.web.authz.handler.AuthorizationHandler;
|
|
||||||
import gr.cite.commons.web.authz.handler.AuthorizationHandlerContext;
|
|
||||||
import gr.cite.commons.web.authz.policy.AuthorizationRequirement;
|
|
||||||
import gr.cite.commons.web.oidc.principal.MyPrincipal;
|
|
||||||
import gr.cite.annotation.authorization.OwnedAuthorizationRequirement;
|
|
||||||
import gr.cite.annotation.authorization.OwnedResource;
|
|
||||||
import gr.cite.annotation.common.scope.user.UserScope;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
|
|
||||||
@Component("ownedAuthorizationHandler")
|
|
||||||
public class OwnedAuthorizationHandler extends AuthorizationHandler<OwnedAuthorizationRequirement> {
|
|
||||||
|
|
||||||
private final UserScope userScope;
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
public OwnedAuthorizationHandler(UserScope userScope) {
|
|
||||||
this.userScope = userScope;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int handleRequirement(AuthorizationHandlerContext context, Object resource, AuthorizationRequirement requirement) {
|
|
||||||
OwnedAuthorizationRequirement req = (OwnedAuthorizationRequirement) requirement;
|
|
||||||
|
|
||||||
OwnedResource rs = (OwnedResource) resource;
|
|
||||||
|
|
||||||
boolean isAuthenticated = ((MyPrincipal) context.getPrincipal()).isAuthenticated();
|
|
||||||
if (!isAuthenticated) return ACCESS_NOT_DETERMINED;
|
|
||||||
|
|
||||||
if (this.userScope.getUserIdSafe() == null) return ACCESS_NOT_DETERMINED;
|
|
||||||
|
|
||||||
if (rs != null && rs.getUserIds() != null && rs.getUserIds().contains(this.userScope.getUserIdSafe())) return ACCESS_GRANTED;
|
|
||||||
|
|
||||||
return ACCESS_NOT_DETERMINED;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Class<? extends AuthorizationRequirement> supporting() {
|
|
||||||
return OwnedAuthorizationRequirement.class;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,25 +0,0 @@
|
||||||
package gr.cite.annotation.web.config;
|
|
||||||
|
|
||||||
import org.springframework.context.MessageSource;
|
|
||||||
import org.springframework.context.annotation.Bean;
|
|
||||||
import org.springframework.context.annotation.Configuration;
|
|
||||||
import org.springframework.context.support.ReloadableResourceBundleMessageSource;
|
|
||||||
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
|
|
||||||
|
|
||||||
@Configuration
|
|
||||||
public class AppMessageSourceConfiguration {
|
|
||||||
@Bean
|
|
||||||
public MessageSource messageSource() {
|
|
||||||
ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();
|
|
||||||
messageSource.setBasename("classpath:messages/messages");
|
|
||||||
messageSource.setDefaultEncoding("UTF-8");
|
|
||||||
return messageSource;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
public LocalValidatorFactoryBean getValidator() {
|
|
||||||
LocalValidatorFactoryBean bean = new LocalValidatorFactoryBean();
|
|
||||||
bean.setValidationMessageSource(messageSource());
|
|
||||||
return bean;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,152 +0,0 @@
|
||||||
package gr.cite.annotation.web.config;
|
|
||||||
|
|
||||||
import gr.cite.annotation.authorization.AffiliatedAuthorizationRequirement;
|
|
||||||
import gr.cite.annotation.authorization.AffiliatedResource;
|
|
||||||
import gr.cite.annotation.web.authorization.AffiliatedAuthorizationHandler;
|
|
||||||
import gr.cite.commons.web.authz.handler.AuthorizationHandler;
|
|
||||||
import gr.cite.commons.web.authz.handler.PermissionClientAuthorizationHandler;
|
|
||||||
import gr.cite.commons.web.authz.policy.AuthorizationRequirement;
|
|
||||||
import gr.cite.commons.web.authz.policy.AuthorizationRequirementMapper;
|
|
||||||
import gr.cite.commons.web.authz.policy.AuthorizationResource;
|
|
||||||
import gr.cite.commons.web.authz.policy.resolver.AuthorizationPolicyConfigurer;
|
|
||||||
import gr.cite.commons.web.authz.policy.resolver.AuthorizationPolicyResolverStrategy;
|
|
||||||
import gr.cite.commons.web.oidc.configuration.WebSecurityProperties;
|
|
||||||
import gr.cite.annotation.authorization.OwnedAuthorizationRequirement;
|
|
||||||
import gr.cite.annotation.authorization.OwnedResource;
|
|
||||||
import gr.cite.annotation.web.authorization.OwnedAuthorizationHandler;
|
|
||||||
import jakarta.servlet.Filter;
|
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.beans.factory.annotation.Qualifier;
|
|
||||||
import org.springframework.context.annotation.Bean;
|
|
||||||
import org.springframework.context.annotation.Configuration;
|
|
||||||
import org.springframework.security.authentication.AuthenticationManagerResolver;
|
|
||||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
|
||||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
|
||||||
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
|
|
||||||
import org.springframework.security.config.annotation.web.configurers.HeadersConfigurer;
|
|
||||||
import org.springframework.security.config.http.SessionCreationPolicy;
|
|
||||||
import org.springframework.security.web.SecurityFilterChain;
|
|
||||||
import org.springframework.security.web.authentication.preauth.AbstractPreAuthenticatedProcessingFilter;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
@Configuration
|
|
||||||
@EnableWebSecurity
|
|
||||||
public class SecurityConfiguration {
|
|
||||||
|
|
||||||
private final WebSecurityProperties webSecurityProperties;
|
|
||||||
private final AuthenticationManagerResolver<HttpServletRequest> authenticationManagerResolver;
|
|
||||||
private final Filter apiKeyFilter;
|
|
||||||
private final OwnedAuthorizationHandler ownedAuthorizationHandler;
|
|
||||||
private final AffiliatedAuthorizationHandler affiliatedAuthorizationHandler;
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
public SecurityConfiguration(WebSecurityProperties webSecurityProperties,
|
|
||||||
@Qualifier("tokenAuthenticationResolver") AuthenticationManagerResolver<HttpServletRequest> authenticationManagerResolver,
|
|
||||||
@Qualifier("apiKeyFilter") Filter apiKeyFilter,
|
|
||||||
@Qualifier("ownedAuthorizationHandler") OwnedAuthorizationHandler ownedAuthorizationHandler,
|
|
||||||
@Qualifier("affiliatedAuthorizationHandler") AffiliatedAuthorizationHandler affiliatedAuthorizationHandler) {
|
|
||||||
this.webSecurityProperties = webSecurityProperties;
|
|
||||||
this.authenticationManagerResolver = authenticationManagerResolver;
|
|
||||||
this.apiKeyFilter = apiKeyFilter;
|
|
||||||
this.ownedAuthorizationHandler = ownedAuthorizationHandler;
|
|
||||||
this.affiliatedAuthorizationHandler = affiliatedAuthorizationHandler;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
|
|
||||||
HttpSecurity tempHttp = http
|
|
||||||
.csrf(AbstractHttpConfigurer::disable)
|
|
||||||
.cors(httpSecurityCorsConfigurer -> {})
|
|
||||||
.headers(httpSecurityHeadersConfigurer -> httpSecurityHeadersConfigurer.frameOptions(HeadersConfigurer.FrameOptionsConfig::disable))
|
|
||||||
.addFilterBefore(apiKeyFilter, AbstractPreAuthenticatedProcessingFilter.class)
|
|
||||||
.authorizeHttpRequests(authRequest ->
|
|
||||||
authRequest.requestMatchers(buildAntPatterns(webSecurityProperties.getAllowedEndpoints())).anonymous()
|
|
||||||
.requestMatchers(buildAntPatterns(webSecurityProperties.getAuthorizedEndpoints())).authenticated())
|
|
||||||
.sessionManagement( sessionManagementConfigurer-> sessionManagementConfigurer.sessionCreationPolicy(SessionCreationPolicy.NEVER))
|
|
||||||
.oauth2ResourceServer(oauth2 -> oauth2.authenticationManagerResolver(authenticationManagerResolver));
|
|
||||||
return tempHttp.build();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
AuthorizationPolicyConfigurer authorizationPolicyConfigurer() {
|
|
||||||
return new AuthorizationPolicyConfigurer() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public AuthorizationPolicyResolverStrategy strategy() {
|
|
||||||
return AuthorizationPolicyResolverStrategy.STRICT_CONSENSUS_BASED;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Here you can register your custom authorization handlers, which will get used as well as the existing ones
|
|
||||||
//This is optional and can be omitted
|
|
||||||
//If not set / set to null, only the default authorization handlers will be used
|
|
||||||
@Override
|
|
||||||
public List<AuthorizationHandler<? extends AuthorizationRequirement>> addCustomHandlers() {
|
|
||||||
return List.of(affiliatedAuthorizationHandler, ownedAuthorizationHandler);
|
|
||||||
}
|
|
||||||
|
|
||||||
//Here you can register your custom authorization requirements (if any)
|
|
||||||
//This is optional and can be omitted
|
|
||||||
//If not set / set to null, only the default authorization requirements will be used
|
|
||||||
@Override
|
|
||||||
public List<? extends AuthorizationRequirement> extendRequirements() {
|
|
||||||
return List.of(
|
|
||||||
// new TimeOfDayAuthorizationRequirement(new TimeOfDay("08:00","16:00"), true)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
//Here you can select handlers you want to disable by providing the classes they are implemented by
|
|
||||||
//You can disable any handler (including any custom one)
|
|
||||||
//This is optional and can be omitted
|
|
||||||
//If not set / set to null, all the handlers will be invoked, based on their requirement support
|
|
||||||
//In the example below, the default client handler will be ignored by the resolver
|
|
||||||
@Override
|
|
||||||
public List<Class<? extends AuthorizationHandler<? extends AuthorizationRequirement>>> disableHandlers() {
|
|
||||||
return new ArrayList<>();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
AuthorizationRequirementMapper authorizationRequirementMapper() {
|
|
||||||
return new AuthorizationRequirementMapper() {
|
|
||||||
@Override
|
|
||||||
public AuthorizationRequirement map(AuthorizationResource resource, boolean matchAll, String[] permissions) {
|
|
||||||
Class<?> type = resource.getClass();
|
|
||||||
if (!AuthorizationResource.class.isAssignableFrom(type)) throw new IllegalArgumentException("resource");
|
|
||||||
|
|
||||||
if (OwnedResource.class.equals(type)) {
|
|
||||||
return new OwnedAuthorizationRequirement();
|
|
||||||
}
|
|
||||||
if (AffiliatedResource.class.equals(type)) {
|
|
||||||
return new AffiliatedAuthorizationRequirement(matchAll, permissions);
|
|
||||||
}
|
|
||||||
throw new IllegalArgumentException("resource");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private String[] buildAntPatterns(Set<String> endpoints) {
|
|
||||||
if (endpoints == null) {
|
|
||||||
return new String[0];
|
|
||||||
}
|
|
||||||
return endpoints.stream()
|
|
||||||
.filter(endpoint -> endpoint != null && !endpoint.isBlank())
|
|
||||||
.map(endpoint -> "/" + stripUnnecessaryCharacters(endpoint) + "/**")
|
|
||||||
.toArray(String[]::new);
|
|
||||||
}
|
|
||||||
|
|
||||||
private String stripUnnecessaryCharacters(String endpoint) {
|
|
||||||
endpoint = endpoint.strip();
|
|
||||||
if (endpoint.startsWith("/")) {
|
|
||||||
endpoint = endpoint.substring(1);
|
|
||||||
}
|
|
||||||
if (endpoint.endsWith("/")) {
|
|
||||||
endpoint = endpoint.substring(0, endpoint.length() - 1);
|
|
||||||
}
|
|
||||||
return endpoint;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,193 +0,0 @@
|
||||||
package gr.cite.annotation.web.controllerhandler;
|
|
||||||
|
|
||||||
import gr.cite.annotation.common.JsonHandlingService;
|
|
||||||
import gr.cite.tools.exception.*;
|
|
||||||
import gr.cite.tools.logging.LoggerService;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
import org.springframework.http.HttpStatus;
|
|
||||||
import org.springframework.http.ResponseEntity;
|
|
||||||
import org.springframework.web.bind.annotation.ControllerAdvice;
|
|
||||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
|
||||||
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
|
||||||
import org.springframework.web.context.request.WebRequest;
|
|
||||||
|
|
||||||
import java.text.MessageFormat;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
@RestControllerAdvice
|
|
||||||
@ControllerAdvice
|
|
||||||
public class GlobalExceptionHandler {
|
|
||||||
private static final LoggerService logger = new LoggerService(LoggerFactory.getLogger(GlobalExceptionHandler.class));
|
|
||||||
|
|
||||||
private final JsonHandlingService jsonHandlingService;
|
|
||||||
|
|
||||||
public GlobalExceptionHandler(JsonHandlingService jsonHandlingService) {
|
|
||||||
this.jsonHandlingService = jsonHandlingService;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@ExceptionHandler(Exception.class)
|
|
||||||
public ResponseEntity<?> handleUnexpectedErrors(Exception exception, WebRequest request) throws Exception {
|
|
||||||
HandledException handled = this.handleException(exception, request);
|
|
||||||
this.log(handled.getLevel(), exception, MessageFormat.format("returning code {0} and payload {1}", handled.getStatusCode(), handled.getMessage()));
|
|
||||||
return new ResponseEntity<>(handled.getMessage(), handled.getStatusCode());
|
|
||||||
}
|
|
||||||
|
|
||||||
public void log(System.Logger.Level level, Exception e, String message) {
|
|
||||||
if (level != null) {
|
|
||||||
switch (level) {
|
|
||||||
case TRACE:
|
|
||||||
logger.trace(message, e);
|
|
||||||
break;
|
|
||||||
case DEBUG:
|
|
||||||
logger.debug(message, e);
|
|
||||||
break;
|
|
||||||
case INFO:
|
|
||||||
logger.info(message, e);
|
|
||||||
break;
|
|
||||||
case WARNING:
|
|
||||||
logger.warn(message, e);
|
|
||||||
break;
|
|
||||||
case ERROR:
|
|
||||||
logger.error(message, e);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public HandledException handleException(Exception exception, WebRequest request) throws Exception {
|
|
||||||
HttpStatus statusCode;
|
|
||||||
Map<String, Object> result;
|
|
||||||
System.Logger.Level logLevel;
|
|
||||||
|
|
||||||
switch (exception){
|
|
||||||
case MyNotFoundException myNotFoundException -> {
|
|
||||||
logLevel = System.Logger.Level.DEBUG;
|
|
||||||
statusCode = HttpStatus.NOT_FOUND;
|
|
||||||
int code = myNotFoundException.getCode();
|
|
||||||
if (code > 0) {
|
|
||||||
result = Map.ofEntries(
|
|
||||||
Map.entry("code", code),
|
|
||||||
Map.entry("error", myNotFoundException.getMessage())
|
|
||||||
);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
result = Map.ofEntries(
|
|
||||||
Map.entry("error", myNotFoundException.getMessage())
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case MyUnauthorizedException myUnauthorizedException -> {
|
|
||||||
logLevel = System.Logger.Level.DEBUG;
|
|
||||||
statusCode = HttpStatus.UNAUTHORIZED;
|
|
||||||
int code = myUnauthorizedException.getCode();
|
|
||||||
if (code > 0) {
|
|
||||||
result = Map.ofEntries(
|
|
||||||
Map.entry("code", code),
|
|
||||||
Map.entry("error", myUnauthorizedException.getMessage())
|
|
||||||
);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
result = Map.ofEntries(
|
|
||||||
Map.entry("error", myUnauthorizedException.getMessage())
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case MyForbiddenException myForbiddenException -> {
|
|
||||||
logLevel = System.Logger.Level.DEBUG;
|
|
||||||
statusCode = HttpStatus.FORBIDDEN;
|
|
||||||
int code = myForbiddenException.getCode();
|
|
||||||
if (code > 0) {
|
|
||||||
result = Map.ofEntries(
|
|
||||||
Map.entry("code", code),
|
|
||||||
Map.entry("error", myForbiddenException.getMessage())
|
|
||||||
);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
result = Map.ofEntries(
|
|
||||||
Map.entry("error", myForbiddenException.getMessage())
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case MyValidationException myValidationException -> {
|
|
||||||
logLevel = System.Logger.Level.DEBUG;
|
|
||||||
statusCode = HttpStatus.BAD_REQUEST;
|
|
||||||
int code = myValidationException.getCode();
|
|
||||||
if (code > 0) {
|
|
||||||
result = Map.ofEntries(
|
|
||||||
Map.entry("code", code),
|
|
||||||
Map.entry("error", myValidationException.getMessage()),
|
|
||||||
Map.entry("message", myValidationException.getErrors())
|
|
||||||
);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
result = Map.ofEntries(
|
|
||||||
Map.entry("error", myValidationException.getMessage()),
|
|
||||||
Map.entry("message", myValidationException.getErrors())
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case MyApplicationException myApplicationException -> {
|
|
||||||
logLevel = System.Logger.Level.ERROR;
|
|
||||||
statusCode = HttpStatus.INTERNAL_SERVER_ERROR;
|
|
||||||
int code = myApplicationException.getCode();
|
|
||||||
if (code > 0) {
|
|
||||||
result = Map.ofEntries(
|
|
||||||
Map.entry("code", code),
|
|
||||||
Map.entry("error", myApplicationException.getMessage())
|
|
||||||
);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
result = Map.ofEntries(
|
|
||||||
Map.entry("error", myApplicationException.getMessage())
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
default -> {
|
|
||||||
logLevel = System.Logger.Level.ERROR;
|
|
||||||
statusCode = HttpStatus.INTERNAL_SERVER_ERROR;
|
|
||||||
result = Map.ofEntries(
|
|
||||||
Map.entry("error", "System error")
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
String serialization = this.jsonHandlingService.toJsonSafe(result);
|
|
||||||
return new HandledException(statusCode, serialization, logLevel);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class HandledException{
|
|
||||||
public HttpStatus statusCode;
|
|
||||||
public String message;
|
|
||||||
public System.Logger.Level level;
|
|
||||||
|
|
||||||
public HandledException(HttpStatus statusCode, String message, System.Logger.Level level) {
|
|
||||||
this.statusCode = statusCode;
|
|
||||||
this.message = message;
|
|
||||||
this.level = level;
|
|
||||||
}
|
|
||||||
|
|
||||||
public HttpStatus getStatusCode() {
|
|
||||||
return statusCode;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setStatusCode(HttpStatus statusCode) {
|
|
||||||
this.statusCode = statusCode;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getMessage() {
|
|
||||||
return message;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setMessage(String message) {
|
|
||||||
this.message = message;
|
|
||||||
}
|
|
||||||
|
|
||||||
public System.Logger.Level getLevel() {
|
|
||||||
return level;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setLevel(System.Logger.Level level) {
|
|
||||||
this.level = level;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,132 +0,0 @@
|
||||||
package gr.cite.annotation.web.controllers;
|
|
||||||
|
|
||||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
|
||||||
import gr.cite.annotation.audit.AuditableAction;
|
|
||||||
import gr.cite.annotation.authorization.AuthorizationFlags;
|
|
||||||
import gr.cite.annotation.data.AnnotationEntity;
|
|
||||||
import gr.cite.annotation.model.Annotation;
|
|
||||||
import gr.cite.annotation.model.builder.AnnotationBuilder;
|
|
||||||
import gr.cite.annotation.model.censorship.AnnotationCensor;
|
|
||||||
import gr.cite.annotation.model.persist.AnnotationPersist;
|
|
||||||
import gr.cite.annotation.query.AnnotationQuery;
|
|
||||||
import gr.cite.annotation.query.lookup.AnnotationLookup;
|
|
||||||
import gr.cite.annotation.service.annotation.AnnotationService;
|
|
||||||
import gr.cite.annotation.web.model.QueryResult;
|
|
||||||
import gr.cite.tools.auditing.AuditService;
|
|
||||||
import gr.cite.tools.data.builder.BuilderFactory;
|
|
||||||
import gr.cite.tools.data.censor.CensorFactory;
|
|
||||||
import gr.cite.tools.data.query.QueryFactory;
|
|
||||||
import gr.cite.tools.exception.MyApplicationException;
|
|
||||||
import gr.cite.tools.exception.MyForbiddenException;
|
|
||||||
import gr.cite.tools.exception.MyNotFoundException;
|
|
||||||
import gr.cite.tools.fieldset.FieldSet;
|
|
||||||
import gr.cite.tools.logging.LoggerService;
|
|
||||||
import gr.cite.tools.logging.MapLogEntry;
|
|
||||||
import gr.cite.tools.validation.ValidationFilterAnnotation;
|
|
||||||
import jakarta.transaction.Transactional;
|
|
||||||
import jakarta.xml.bind.JAXBException;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
import org.springframework.context.MessageSource;
|
|
||||||
import org.springframework.context.i18n.LocaleContextHolder;
|
|
||||||
import org.springframework.http.MediaType;
|
|
||||||
import org.springframework.web.bind.annotation.*;
|
|
||||||
|
|
||||||
import javax.management.InvalidApplicationException;
|
|
||||||
import javax.xml.parsers.ParserConfigurationException;
|
|
||||||
import javax.xml.transform.TransformerException;
|
|
||||||
import java.util.AbstractMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
@RestController
|
|
||||||
@RequestMapping(path = "api/annotation", produces = MediaType.APPLICATION_JSON_VALUE)
|
|
||||||
public class AnnotationController {
|
|
||||||
|
|
||||||
private static final LoggerService logger = new LoggerService(LoggerFactory.getLogger(AnnotationController.class));
|
|
||||||
|
|
||||||
private final CensorFactory censorFactory;
|
|
||||||
|
|
||||||
private final QueryFactory queryFactory;
|
|
||||||
|
|
||||||
private final BuilderFactory builderFactory;
|
|
||||||
|
|
||||||
private final AuditService auditService;
|
|
||||||
|
|
||||||
private final MessageSource messageSource;
|
|
||||||
|
|
||||||
private final AnnotationService annotationService;
|
|
||||||
|
|
||||||
public AnnotationController(CensorFactory censorFactory, QueryFactory queryFactory, BuilderFactory builderFactory, AuditService auditService, MessageSource messageSource, AnnotationService annotationService) {
|
|
||||||
this.censorFactory = censorFactory;
|
|
||||||
this.queryFactory = queryFactory;
|
|
||||||
this.builderFactory = builderFactory;
|
|
||||||
this.auditService = auditService;
|
|
||||||
this.messageSource = messageSource;
|
|
||||||
this.annotationService = annotationService;
|
|
||||||
}
|
|
||||||
|
|
||||||
@PostMapping("query")
|
|
||||||
public QueryResult<Annotation> query(@RequestBody AnnotationLookup lookup) {
|
|
||||||
logger.debug("querying {}", Annotation.class.getSimpleName());
|
|
||||||
|
|
||||||
this.censorFactory.censor(AnnotationCensor.class).censor(lookup.getProject(), null);
|
|
||||||
|
|
||||||
AnnotationQuery query = lookup.enrich(this.queryFactory).disableTracking().authorize(AuthorizationFlags.OwnerOrPermissionAssociated);
|
|
||||||
List<AnnotationEntity> data = query.collect();
|
|
||||||
List<Annotation> models = this.builderFactory.builder(AnnotationBuilder.class).authorize(AuthorizationFlags.OwnerOrPermissionAssociated).build(lookup.getProject(), data);
|
|
||||||
long count = (lookup.getMetadata() != null && lookup.getMetadata().getCountAll()) ? query.count() : models.size();
|
|
||||||
|
|
||||||
this.auditService.track(AuditableAction.Annotation_Query, "lookup", lookup);
|
|
||||||
|
|
||||||
return new QueryResult<>(models, count);
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("{id}")
|
|
||||||
public Annotation get(@PathVariable("id") UUID id, FieldSet fieldSet) throws MyApplicationException, MyForbiddenException, MyNotFoundException {
|
|
||||||
logger.debug(new MapLogEntry("retrieving" + Annotation.class.getSimpleName()).And("id", id).And("fields", fieldSet));
|
|
||||||
|
|
||||||
this.censorFactory.censor(AnnotationCensor.class).censor(fieldSet, null);
|
|
||||||
|
|
||||||
AnnotationQuery query = this.queryFactory.query(AnnotationQuery.class).disableTracking().authorize(AuthorizationFlags.OwnerOrPermissionAssociated).ids(id);
|
|
||||||
Annotation model = this.builderFactory.builder(AnnotationBuilder.class).authorize(AuthorizationFlags.OwnerOrPermissionAssociated).build(fieldSet, query.firstAs(fieldSet));
|
|
||||||
if (model == null)
|
|
||||||
throw new MyNotFoundException(messageSource.getMessage("General_ItemNotFound", new Object[]{id, Annotation.class.getSimpleName()}, LocaleContextHolder.getLocale()));
|
|
||||||
|
|
||||||
this.auditService.track(AuditableAction.Annotation_Lookup, Map.ofEntries(
|
|
||||||
new AbstractMap.SimpleEntry<String, Object>("id", id),
|
|
||||||
new AbstractMap.SimpleEntry<String, Object>("fields", fieldSet)
|
|
||||||
));
|
|
||||||
|
|
||||||
return model;
|
|
||||||
}
|
|
||||||
|
|
||||||
@PostMapping("persist")
|
|
||||||
@Transactional
|
|
||||||
@ValidationFilterAnnotation(validator = AnnotationPersist.AnnotationPersistValidator.ValidatorName, argumentName = "model")
|
|
||||||
public Annotation persist(@RequestBody AnnotationPersist model, FieldSet fieldSet) throws MyApplicationException, MyForbiddenException, MyNotFoundException, InvalidApplicationException, JAXBException, ParserConfigurationException, JsonProcessingException, TransformerException {
|
|
||||||
logger.debug(new MapLogEntry("persisting" + Annotation.class.getSimpleName()).And("model", model).And("fieldSet", fieldSet));
|
|
||||||
|
|
||||||
this.censorFactory.censor(AnnotationCensor.class).censor(fieldSet, null);
|
|
||||||
|
|
||||||
Annotation persisted = this.annotationService.persist(model, fieldSet);
|
|
||||||
|
|
||||||
this.auditService.track(AuditableAction.Annotation_Persist, Map.ofEntries(
|
|
||||||
new AbstractMap.SimpleEntry<String, Object>("model", model),
|
|
||||||
new AbstractMap.SimpleEntry<String, Object>("fields", fieldSet)
|
|
||||||
));
|
|
||||||
|
|
||||||
return persisted;
|
|
||||||
}
|
|
||||||
|
|
||||||
@DeleteMapping("{id}")
|
|
||||||
@Transactional
|
|
||||||
public void delete(@PathVariable("id") UUID id) throws MyForbiddenException, InvalidApplicationException {
|
|
||||||
logger.debug(new MapLogEntry("retrieving" + Annotation.class.getSimpleName()).And("id", id));
|
|
||||||
|
|
||||||
this.annotationService.deleteAndSave(id);
|
|
||||||
|
|
||||||
this.auditService.track(AuditableAction.Annotation_Delete, "id", id);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,76 +0,0 @@
|
||||||
package gr.cite.annotation.web.controllers;
|
|
||||||
|
|
||||||
import gr.cite.annotation.authorization.ClaimNames;
|
|
||||||
import gr.cite.commons.web.oidc.principal.CurrentPrincipalResolver;
|
|
||||||
import gr.cite.commons.web.oidc.principal.MyPrincipal;
|
|
||||||
import gr.cite.commons.web.oidc.principal.extractor.ClaimExtractor;
|
|
||||||
import gr.cite.annotation.audit.AuditableAction;
|
|
||||||
import gr.cite.annotation.common.scope.tenant.TenantScope;
|
|
||||||
import gr.cite.annotation.web.model.Account;
|
|
||||||
import gr.cite.annotation.web.model.AccountBuilder;
|
|
||||||
import gr.cite.tools.auditing.AuditService;
|
|
||||||
import gr.cite.tools.fieldset.BaseFieldSet;
|
|
||||||
import gr.cite.tools.fieldset.FieldSet;
|
|
||||||
import gr.cite.tools.logging.LoggerService;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.http.MediaType;
|
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
@RestController
|
|
||||||
@RequestMapping(path = "api/annotation/principal", produces = MediaType.APPLICATION_JSON_VALUE)
|
|
||||||
public class PrincipalController {
|
|
||||||
private static final LoggerService logger = new LoggerService(LoggerFactory.getLogger(PrincipalController.class));
|
|
||||||
private final AuditService auditService;
|
|
||||||
|
|
||||||
private final CurrentPrincipalResolver currentPrincipalResolver;
|
|
||||||
private final AccountBuilder accountBuilder;
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
public PrincipalController(
|
|
||||||
CurrentPrincipalResolver currentPrincipalResolver,
|
|
||||||
AccountBuilder accountBuilder,
|
|
||||||
AuditService auditService) {
|
|
||||||
this.currentPrincipalResolver = currentPrincipalResolver;
|
|
||||||
this.accountBuilder = accountBuilder;
|
|
||||||
this.auditService = auditService;
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("me")
|
|
||||||
public Account me(FieldSet fieldSet) {
|
|
||||||
logger.debug("me");
|
|
||||||
|
|
||||||
|
|
||||||
if (fieldSet == null || fieldSet.isEmpty()) {
|
|
||||||
fieldSet = new BaseFieldSet(
|
|
||||||
Account._isAuthenticated,
|
|
||||||
BaseFieldSet.asIndexer(Account._principal, Account.PrincipalInfo._subject),
|
|
||||||
BaseFieldSet.asIndexer(Account._principal, Account.PrincipalInfo._userId),
|
|
||||||
BaseFieldSet.asIndexer(Account._principal, Account.PrincipalInfo._name),
|
|
||||||
BaseFieldSet.asIndexer(Account._principal, Account.PrincipalInfo._scope),
|
|
||||||
BaseFieldSet.asIndexer(Account._principal, Account.PrincipalInfo._client),
|
|
||||||
BaseFieldSet.asIndexer(Account._principal, Account.PrincipalInfo._issuedAt),
|
|
||||||
BaseFieldSet.asIndexer(Account._principal, Account.PrincipalInfo._notBefore),
|
|
||||||
BaseFieldSet.asIndexer(Account._principal, Account.PrincipalInfo._authenticatedAt),
|
|
||||||
BaseFieldSet.asIndexer(Account._principal, Account.PrincipalInfo._expiresAt),
|
|
||||||
BaseFieldSet.asIndexer(Account._principal, Account.PrincipalInfo._more),
|
|
||||||
Account._permissions);
|
|
||||||
}
|
|
||||||
|
|
||||||
MyPrincipal principal = this.currentPrincipalResolver.currentPrincipal();
|
|
||||||
|
|
||||||
Account me = this.accountBuilder.build(fieldSet, principal);
|
|
||||||
|
|
||||||
this.auditService.track(AuditableAction.Principal_Lookup);
|
|
||||||
//auditService.trackIdentity(AuditableAction.IdentityTracking_Action);
|
|
||||||
|
|
||||||
return me;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,160 +0,0 @@
|
||||||
package gr.cite.annotation.web.model;
|
|
||||||
|
|
||||||
import gr.cite.tools.logging.annotation.LogSensitive;
|
|
||||||
|
|
||||||
import java.time.Instant;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
public class Account {
|
|
||||||
|
|
||||||
public static class PrincipalInfo {
|
|
||||||
|
|
||||||
public static final String _userId = "userId";
|
|
||||||
public UUID userId;
|
|
||||||
|
|
||||||
public UUID getUserId() {
|
|
||||||
return userId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setUserId(UUID userId) {
|
|
||||||
this.userId = userId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static final String _subject = "subject";
|
|
||||||
public UUID subject;
|
|
||||||
|
|
||||||
public UUID getSubject() {
|
|
||||||
return subject;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setSubject(UUID subject) {
|
|
||||||
this.subject = subject;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static final String _name = "name";
|
|
||||||
@LogSensitive
|
|
||||||
public String name;
|
|
||||||
|
|
||||||
public String getName() {
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setName(String name) {
|
|
||||||
this.name = name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static final String _scope = "scope";
|
|
||||||
public List<String> scope;
|
|
||||||
|
|
||||||
public List<String> getScope() {
|
|
||||||
return scope;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setScope(List<String> scope) {
|
|
||||||
this.scope = scope;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static final String _client = "client";
|
|
||||||
public String client;
|
|
||||||
|
|
||||||
public String getClient() {
|
|
||||||
return client;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setClient(String client) {
|
|
||||||
this.client = client;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static final String _notBefore = "notBefore";
|
|
||||||
public Instant notBefore;
|
|
||||||
|
|
||||||
public Instant getNotBefore() {
|
|
||||||
return notBefore;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setNotBefore(Instant notBefore) {
|
|
||||||
this.notBefore = notBefore;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static final String _issuedAt = "issuedAt";
|
|
||||||
public Instant issuedAt;
|
|
||||||
|
|
||||||
public Instant getIssuedAt() {
|
|
||||||
return issuedAt;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setIssuedAt(Instant issuedAt) {
|
|
||||||
this.issuedAt = issuedAt;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static final String _authenticatedAt = "authenticatedAt";
|
|
||||||
public Instant authenticatedAt;
|
|
||||||
|
|
||||||
public Instant getAuthenticatedAt() {
|
|
||||||
return authenticatedAt;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setAuthenticatedAt(Instant authenticatedAt) {
|
|
||||||
this.authenticatedAt = authenticatedAt;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static final String _expiresAt = "expiresAt";
|
|
||||||
public Instant expiresAt;
|
|
||||||
|
|
||||||
public Instant getExpiresAt() {
|
|
||||||
return expiresAt;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setExpiresAt(Instant expiresAt) {
|
|
||||||
this.expiresAt = expiresAt;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static final String _more = "more";
|
|
||||||
@LogSensitive
|
|
||||||
public Map<String, List<String>> more;
|
|
||||||
|
|
||||||
public Map<String, List<String>> getMore() {
|
|
||||||
return more;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setMore(Map<String, List<String>> more) {
|
|
||||||
this.more = more;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public static final String _isAuthenticated = "isAuthenticated";
|
|
||||||
private Boolean isAuthenticated;
|
|
||||||
|
|
||||||
public Boolean getIsAuthenticated() {
|
|
||||||
return isAuthenticated;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setIsAuthenticated(Boolean authenticated) {
|
|
||||||
isAuthenticated = authenticated;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static final String _principal = "principal";
|
|
||||||
private PrincipalInfo principal;
|
|
||||||
|
|
||||||
public PrincipalInfo getPrincipal() {
|
|
||||||
return principal;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setPrincipal(PrincipalInfo principal) {
|
|
||||||
this.principal = principal;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static final String _permissions = "permissions";
|
|
||||||
private List<String> permissions;
|
|
||||||
|
|
||||||
public List<String> getPermissions() {
|
|
||||||
return permissions;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setPermissions(List<String> permissions) {
|
|
||||||
this.permissions = permissions;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,86 +0,0 @@
|
||||||
package gr.cite.annotation.web.model;
|
|
||||||
|
|
||||||
import gr.cite.commons.web.authz.configuration.AuthorizationConfiguration;
|
|
||||||
import gr.cite.commons.web.authz.configuration.Permission;
|
|
||||||
import gr.cite.commons.web.oidc.principal.CurrentPrincipalResolver;
|
|
||||||
import gr.cite.commons.web.oidc.principal.MyPrincipal;
|
|
||||||
import gr.cite.commons.web.oidc.principal.extractor.ClaimExtractor;
|
|
||||||
import gr.cite.commons.web.oidc.principal.extractor.ClaimExtractorKeys;
|
|
||||||
import gr.cite.annotation.common.scope.user.UserScope;
|
|
||||||
import gr.cite.tools.fieldset.BaseFieldSet;
|
|
||||||
import gr.cite.tools.fieldset.FieldSet;
|
|
||||||
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
|
|
||||||
import org.springframework.context.annotation.Scope;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
|
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
@Component
|
|
||||||
@Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE)
|
|
||||||
public class AccountBuilder {
|
|
||||||
|
|
||||||
private final ClaimExtractor claimExtractor;
|
|
||||||
private final Set<String> excludeMoreClaim;
|
|
||||||
private final AuthorizationConfiguration authorizationConfiguration;
|
|
||||||
private final CurrentPrincipalResolver currentPrincipalResolver;
|
|
||||||
private final UserScope userScope;
|
|
||||||
|
|
||||||
public AccountBuilder(ClaimExtractor claimExtractor, AuthorizationConfiguration authorizationConfiguration, CurrentPrincipalResolver currentPrincipalResolver, UserScope userScope) {
|
|
||||||
this.claimExtractor = claimExtractor;
|
|
||||||
this.authorizationConfiguration = authorizationConfiguration;
|
|
||||||
this.currentPrincipalResolver = currentPrincipalResolver;
|
|
||||||
this.userScope = userScope;
|
|
||||||
this.excludeMoreClaim = Set.of(
|
|
||||||
ClaimExtractorKeys.Subject,
|
|
||||||
ClaimExtractorKeys.Name,
|
|
||||||
ClaimExtractorKeys.Scope,
|
|
||||||
ClaimExtractorKeys.Client,
|
|
||||||
ClaimExtractorKeys.IssuedAt,
|
|
||||||
ClaimExtractorKeys.NotBefore,
|
|
||||||
ClaimExtractorKeys.AuthenticatedAt,
|
|
||||||
ClaimExtractorKeys.ExpiresAt);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Account build(FieldSet fields, MyPrincipal principal) {
|
|
||||||
Account model = new Account();
|
|
||||||
if (principal == null || !principal.isAuthenticated()) {
|
|
||||||
model.setIsAuthenticated(false);
|
|
||||||
return model;
|
|
||||||
}
|
|
||||||
model.setIsAuthenticated(true);
|
|
||||||
|
|
||||||
FieldSet principalFields = fields.extractPrefixed(BaseFieldSet.asIndexerPrefix(Account._principal));
|
|
||||||
if (!principalFields.isEmpty()) model.setPrincipal(new Account.PrincipalInfo());
|
|
||||||
if (principalFields.hasField(Account.PrincipalInfo._subject)) model.getPrincipal().setSubject(this.claimExtractor.subjectUUID(principal));
|
|
||||||
if (principalFields.hasField(Account.PrincipalInfo._userId)) model.getPrincipal().setUserId(this.userScope.getUserIdSafe());
|
|
||||||
if (principalFields.hasField(Account.PrincipalInfo._name)) model.getPrincipal().setName(this.claimExtractor.name(principal));
|
|
||||||
if (principalFields.hasField(Account.PrincipalInfo._scope)) model.getPrincipal().setScope(this.claimExtractor.scope(principal));
|
|
||||||
if (principalFields.hasField(Account.PrincipalInfo._client)) model.getPrincipal().setClient(this.claimExtractor.client(principal));
|
|
||||||
if (principalFields.hasField(Account.PrincipalInfo._issuedAt)) model.getPrincipal().setIssuedAt(this.claimExtractor.issuedAt(principal));
|
|
||||||
if (principalFields.hasField(Account.PrincipalInfo._notBefore)) model.getPrincipal().setNotBefore(this.claimExtractor.notBefore(principal));
|
|
||||||
if (principalFields.hasField(Account.PrincipalInfo._authenticatedAt)) model.getPrincipal().setAuthenticatedAt(this.claimExtractor.authenticatedAt(principal));
|
|
||||||
if (principalFields.hasField(Account.PrincipalInfo._expiresAt)) model.getPrincipal().setExpiresAt(this.claimExtractor.expiresAt(principal));
|
|
||||||
if (principalFields.hasField(Account.PrincipalInfo._more)) {
|
|
||||||
model.getPrincipal().setMore(new HashMap<>());
|
|
||||||
for (String key : this.claimExtractor.knownPublicKeys()) {
|
|
||||||
if (this.excludeMoreClaim.contains(key)) continue;
|
|
||||||
List<String> values = this.claimExtractor.asStrings(principal, key);
|
|
||||||
if (values == null || values.size() == 0) continue;
|
|
||||||
if (!model.getPrincipal().getMore().containsKey(key)) model.getPrincipal().getMore().put(key, new ArrayList<>());
|
|
||||||
model.getPrincipal().getMore().get(key).addAll(values);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fields.hasField(Account._permissions)) {
|
|
||||||
List<String> roles = claimExtractor.roles(currentPrincipalResolver.currentPrincipal());
|
|
||||||
Set<String> permissions = authorizationConfiguration.permissionsOfRoles(roles);
|
|
||||||
for (Map.Entry<String, Permission> permissionEntry : authorizationConfiguration.getRawPolicies().entrySet()){
|
|
||||||
if (permissionEntry.getValue().getAllowAuthenticated()){
|
|
||||||
permissions.add(permissionEntry.getKey());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
model.setPermissions(new ArrayList<>(permissions));
|
|
||||||
}
|
|
||||||
return model;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,37 +0,0 @@
|
||||||
package gr.cite.annotation.web.model;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class QueryResult<M> {
|
|
||||||
public QueryResult() { }
|
|
||||||
public QueryResult(List<M> items, long count)
|
|
||||||
{
|
|
||||||
this.items = items;
|
|
||||||
this.count = count;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<M> items;
|
|
||||||
public long count;
|
|
||||||
|
|
||||||
public List<M> getItems() {
|
|
||||||
return items;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setItems(List<M> items) {
|
|
||||||
this.items = items;
|
|
||||||
}
|
|
||||||
|
|
||||||
public long getCount() {
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setCount(long count) {
|
|
||||||
this.count = count;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static QueryResult<?> Empty()
|
|
||||||
{
|
|
||||||
return new QueryResult<>(new ArrayList<>(), 0L);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,10 +0,0 @@
|
||||||
package gr.cite.annotation.web.scope.tenant;
|
|
||||||
|
|
||||||
import gr.cite.tools.cache.CacheOptions;
|
|
||||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
|
||||||
import org.springframework.context.annotation.Configuration;
|
|
||||||
|
|
||||||
@Configuration
|
|
||||||
@ConfigurationProperties(prefix = "cache.tenant-by-code")
|
|
||||||
public class TenantByCodeCacheOptions extends CacheOptions {
|
|
||||||
}
|
|
|
@ -1,76 +0,0 @@
|
||||||
package gr.cite.annotation.web.scope.tenant;
|
|
||||||
|
|
||||||
import gr.cite.annotation.convention.ConventionService;
|
|
||||||
import gr.cite.annotation.event.TenantTouchedEvent;
|
|
||||||
import gr.cite.tools.cache.CacheService;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.context.event.EventListener;
|
|
||||||
import org.springframework.stereotype.Service;
|
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
@Service
|
|
||||||
public class TenantByCodeCacheService extends CacheService<TenantByCodeCacheService.TenantByCodeCacheValue> {
|
|
||||||
|
|
||||||
public static class TenantByCodeCacheValue {
|
|
||||||
|
|
||||||
public TenantByCodeCacheValue() {
|
|
||||||
}
|
|
||||||
|
|
||||||
public TenantByCodeCacheValue(String tenantCode, UUID tenantId) {
|
|
||||||
this.tenantCode = tenantCode;
|
|
||||||
this.tenantId = tenantId;
|
|
||||||
}
|
|
||||||
|
|
||||||
private String tenantCode;
|
|
||||||
|
|
||||||
public String getTenantCode() {
|
|
||||||
return tenantCode;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setTenantCode(String tenantCode) {
|
|
||||||
this.tenantCode = tenantCode;
|
|
||||||
}
|
|
||||||
|
|
||||||
private UUID tenantId;
|
|
||||||
|
|
||||||
public UUID getTenantId() {
|
|
||||||
return tenantId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setTenantId(UUID tenantId) {
|
|
||||||
this.tenantId = tenantId;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private final ConventionService conventionService;
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
public TenantByCodeCacheService(TenantByCodeCacheOptions options, ConventionService conventionService) {
|
|
||||||
super(options);
|
|
||||||
this.conventionService = conventionService;
|
|
||||||
}
|
|
||||||
|
|
||||||
@EventListener
|
|
||||||
public void handleTenantTouchedEvent(TenantTouchedEvent event) {
|
|
||||||
if (!this.conventionService.isNullOrEmpty(event.getTenantCode()))
|
|
||||||
this.evict(this.buildKey(event.getTenantCode()));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Class<TenantByCodeCacheValue> valueClass() {
|
|
||||||
return TenantByCodeCacheValue.class;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String keyOf(TenantByCodeCacheValue value) {
|
|
||||||
return this.buildKey(value.getTenantCode());
|
|
||||||
}
|
|
||||||
|
|
||||||
public String buildKey(String code) {
|
|
||||||
HashMap<String, String> keyParts = new HashMap<>();
|
|
||||||
keyParts.put("$code$", code);
|
|
||||||
return this.generateKey(keyParts);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,10 +0,0 @@
|
||||||
package gr.cite.annotation.web.scope.tenant;
|
|
||||||
|
|
||||||
import gr.cite.tools.cache.CacheOptions;
|
|
||||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
|
||||||
import org.springframework.context.annotation.Configuration;
|
|
||||||
|
|
||||||
@Configuration
|
|
||||||
@ConfigurationProperties(prefix = "cache.tenant-by-id")
|
|
||||||
public class TenantByIdCacheOptions extends CacheOptions {
|
|
||||||
}
|
|
|
@ -1,75 +0,0 @@
|
||||||
package gr.cite.annotation.web.scope.tenant;
|
|
||||||
|
|
||||||
import gr.cite.annotation.convention.ConventionService;
|
|
||||||
import gr.cite.annotation.event.TenantTouchedEvent;
|
|
||||||
import gr.cite.tools.cache.CacheService;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.context.event.EventListener;
|
|
||||||
import org.springframework.stereotype.Service;
|
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Locale;
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
@Service
|
|
||||||
public class TenantByIdCacheService extends CacheService<TenantByIdCacheService.TenantByIdCacheValue> {
|
|
||||||
|
|
||||||
public static class TenantByIdCacheValue {
|
|
||||||
|
|
||||||
public TenantByIdCacheValue() {
|
|
||||||
}
|
|
||||||
|
|
||||||
public TenantByIdCacheValue(String tenantCode, UUID tenantId) {
|
|
||||||
this.tenantCode = tenantCode;
|
|
||||||
this.tenantId = tenantId;
|
|
||||||
}
|
|
||||||
|
|
||||||
private String tenantCode;
|
|
||||||
|
|
||||||
public String getTenantCode() {
|
|
||||||
return tenantCode;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setTenantCode(String tenantCode) {
|
|
||||||
this.tenantCode = tenantCode;
|
|
||||||
}
|
|
||||||
|
|
||||||
private UUID tenantId;
|
|
||||||
|
|
||||||
public UUID getTenantId() {
|
|
||||||
return tenantId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setTenantId(UUID tenantId) {
|
|
||||||
this.tenantId = tenantId;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
public TenantByIdCacheService(TenantByIdCacheOptions options) {
|
|
||||||
super(options);
|
|
||||||
}
|
|
||||||
|
|
||||||
@EventListener
|
|
||||||
public void handleTenantTouchedEvent(TenantTouchedEvent event) {
|
|
||||||
if (event.getTenantId() != null)
|
|
||||||
this.evict(this.buildKey(event.getTenantId()));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Class<TenantByIdCacheValue> valueClass() {
|
|
||||||
return TenantByIdCacheValue.class;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String keyOf(TenantByIdCacheValue value) {
|
|
||||||
return this.buildKey(value.getTenantId());
|
|
||||||
}
|
|
||||||
|
|
||||||
public String buildKey(UUID id) {
|
|
||||||
HashMap<String, String> keyParts = new HashMap<>();
|
|
||||||
keyParts.put("$tenantId$", id.toString().toLowerCase(Locale.ROOT));
|
|
||||||
return this.generateKey(keyParts);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,183 +0,0 @@
|
||||||
package gr.cite.annotation.web.scope.tenant;
|
|
||||||
|
|
||||||
|
|
||||||
import gr.cite.annotation.authorization.ClaimNames;
|
|
||||||
import gr.cite.annotation.authorization.Permission;
|
|
||||||
import gr.cite.annotation.common.enums.IsActive;
|
|
||||||
import gr.cite.annotation.common.scope.tenant.TenantScope;
|
|
||||||
import gr.cite.annotation.common.scope.user.UserScope;
|
|
||||||
import gr.cite.annotation.data.TenantEntityManager;
|
|
||||||
import gr.cite.annotation.data.TenantUserEntity;
|
|
||||||
import gr.cite.annotation.data.UserEntity;
|
|
||||||
import gr.cite.annotation.data.tenant.TenantScopedBaseEntity;
|
|
||||||
import gr.cite.annotation.errorcode.ErrorThesaurusProperties;
|
|
||||||
import gr.cite.annotation.query.utils.BuildSubQueryInput;
|
|
||||||
import gr.cite.annotation.query.utils.QueryUtilsService;
|
|
||||||
import gr.cite.commons.web.authz.service.AuthorizationService;
|
|
||||||
import gr.cite.commons.web.oidc.principal.CurrentPrincipalResolver;
|
|
||||||
import gr.cite.commons.web.oidc.principal.extractor.ClaimExtractor;
|
|
||||||
import gr.cite.tools.exception.MyForbiddenException;
|
|
||||||
import gr.cite.tools.logging.LoggerService;
|
|
||||||
import jakarta.persistence.EntityManager;
|
|
||||||
import jakarta.persistence.PersistenceContext;
|
|
||||||
import jakarta.persistence.criteria.CriteriaBuilder;
|
|
||||||
import jakarta.persistence.criteria.CriteriaQuery;
|
|
||||||
import jakarta.persistence.criteria.Root;
|
|
||||||
import org.hibernate.Session;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.context.ApplicationContext;
|
|
||||||
import org.springframework.lang.NonNull;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
import org.springframework.ui.ModelMap;
|
|
||||||
import org.springframework.web.context.request.ServletWebRequest;
|
|
||||||
import org.springframework.web.context.request.WebRequest;
|
|
||||||
import org.springframework.web.context.request.WebRequestInterceptor;
|
|
||||||
|
|
||||||
import javax.management.InvalidApplicationException;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Locale;
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
@Component
|
|
||||||
public class TenantInterceptor implements WebRequestInterceptor {
|
|
||||||
|
|
||||||
private static final LoggerService logger = new LoggerService(LoggerFactory.getLogger(TenantInterceptor.class));
|
|
||||||
private final TenantScope tenantScope;
|
|
||||||
private final UserScope userScope;
|
|
||||||
private final CurrentPrincipalResolver currentPrincipalResolver;
|
|
||||||
private final ClaimExtractor claimExtractor;
|
|
||||||
private final ApplicationContext applicationContext;
|
|
||||||
private final TenantScopeProperties tenantScopeProperties;
|
|
||||||
private final UserAllowedTenantCacheService userAllowedTenantCacheService;
|
|
||||||
private final ErrorThesaurusProperties errors;
|
|
||||||
private final QueryUtilsService queryUtilsService;
|
|
||||||
public final TenantEntityManager tenantEntityManager;
|
|
||||||
@PersistenceContext
|
|
||||||
public EntityManager entityManager;
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
public TenantInterceptor(
|
|
||||||
TenantScope tenantScope,
|
|
||||||
UserScope userScope,
|
|
||||||
CurrentPrincipalResolver currentPrincipalResolver,
|
|
||||||
ClaimExtractor claimExtractor,
|
|
||||||
ApplicationContext applicationContext,
|
|
||||||
TenantScopeProperties tenantScopeProperties,
|
|
||||||
UserAllowedTenantCacheService userAllowedTenantCacheService,
|
|
||||||
ErrorThesaurusProperties errors, QueryUtilsService queryUtilsService, TenantEntityManager tenantEntityManager) {
|
|
||||||
this.tenantScope = tenantScope;
|
|
||||||
this.userScope = userScope;
|
|
||||||
this.currentPrincipalResolver = currentPrincipalResolver;
|
|
||||||
this.claimExtractor = claimExtractor;
|
|
||||||
this.applicationContext = applicationContext;
|
|
||||||
this.tenantScopeProperties = tenantScopeProperties;
|
|
||||||
this.userAllowedTenantCacheService = userAllowedTenantCacheService;
|
|
||||||
this.errors = errors;
|
|
||||||
this.queryUtilsService = queryUtilsService;
|
|
||||||
this.tenantEntityManager = tenantEntityManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void preHandle(@NotNull WebRequest request) throws InvalidApplicationException, InterruptedException {
|
|
||||||
if (!this.currentPrincipalResolver.currentPrincipal().isAuthenticated()) return;
|
|
||||||
if (!this.tenantScope.isMultitenant()) return;
|
|
||||||
|
|
||||||
boolean isAllowedNoTenant = this.applicationContext.getBean(AuthorizationService.class).authorize(Permission.AllowNoTenant);
|
|
||||||
if (tenantScope.isSet() && this.entityManager != null) {
|
|
||||||
List<String> currentPrincipalTenantCodes = this.claimExtractor.asStrings(this.currentPrincipalResolver.currentPrincipal(), ClaimNames.TenantCodesClaimName);
|
|
||||||
if ((currentPrincipalTenantCodes == null || !currentPrincipalTenantCodes.contains(tenantScope.getTenantCode())) && !isAllowedNoTenant) {
|
|
||||||
logger.warn("tenant not allowed {}", this.tenantScope.getTenant());
|
|
||||||
throw new MyForbiddenException(this.errors.getTenantNotAllowed().getCode(), this.errors.getTenantNotAllowed().getMessage());
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean isUserAllowedTenant = false;
|
|
||||||
if (this.tenantScope.isDefaultTenant()){
|
|
||||||
isUserAllowedTenant = true;
|
|
||||||
} else {
|
|
||||||
UserAllowedTenantCacheService.UserAllowedTenantCacheValue cacheValue = this.userAllowedTenantCacheService.lookup(this.userAllowedTenantCacheService.buildKey(this.userScope.getUserId(), this.tenantScope.getTenant()));
|
|
||||||
if (cacheValue != null) {
|
|
||||||
isUserAllowedTenant = cacheValue.isAllowed();
|
|
||||||
} else {
|
|
||||||
isUserAllowedTenant = this.isUserAllowedTenant();
|
|
||||||
this.userAllowedTenantCacheService.put(new UserAllowedTenantCacheService.UserAllowedTenantCacheValue(this.userScope.getUserId(), this.tenantScope.getTenant(), isUserAllowedTenant));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isUserAllowedTenant) {
|
|
||||||
this.tenantEntityManager.reloadTenantFilters();
|
|
||||||
} else {
|
|
||||||
if (isAllowedNoTenant || this.isWhiteListedEndpoint(request)) {
|
|
||||||
tenantScope.setTenant(null, null);
|
|
||||||
} else {
|
|
||||||
logger.warn("tenant not allowed {}", this.tenantScope.getTenant());
|
|
||||||
throw new MyForbiddenException(this.errors.getTenantNotAllowed().getCode(), this.errors.getTenantNotAllowed().getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (!isAllowedNoTenant) {
|
|
||||||
if (!this.isWhiteListedEndpoint(request)) {
|
|
||||||
logger.warn("tenant scope not provided");
|
|
||||||
throw new MyForbiddenException(this.errors.getMissingTenant().getCode(), this.errors.getMissingTenant().getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isWhiteListedEndpoint(WebRequest request) {
|
|
||||||
String servletPath = ((ServletWebRequest) request).getRequest().getServletPath();
|
|
||||||
if (this.tenantScopeProperties.getWhiteListedEndpoints() != null) {
|
|
||||||
for (String whiteListedEndpoint : this.tenantScopeProperties.getWhiteListedEndpoints()) {
|
|
||||||
if (servletPath.toLowerCase(Locale.ROOT).startsWith(whiteListedEndpoint.toLowerCase(Locale.ROOT))) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isUserAllowedTenant() throws InvalidApplicationException, InterruptedException {
|
|
||||||
if (userScope.isSet()) {
|
|
||||||
CriteriaBuilder criteriaBuilder = this.entityManager.getCriteriaBuilder();
|
|
||||||
CriteriaQuery<UserEntity> query = criteriaBuilder.createQuery(UserEntity.class);
|
|
||||||
Root<UserEntity> root = query.from(UserEntity.class);
|
|
||||||
query.where(criteriaBuilder.and(
|
|
||||||
criteriaBuilder.equal(root.get(UserEntity._isActive), IsActive.Active),
|
|
||||||
criteriaBuilder.in(root.get(UserEntity._id)).value(queryUtilsService.buildSubQuery(new BuildSubQueryInput<>(new BuildSubQueryInput.Builder<>(TenantUserEntity.class, UUID.class)
|
|
||||||
.query(query)
|
|
||||||
.criteriaBuilder(criteriaBuilder)
|
|
||||||
.keyPathFunc((subQueryRoot) -> subQueryRoot.get(TenantUserEntity._userId))
|
|
||||||
.filterFunc((subQueryRoot, cb) ->
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
return cb.and(
|
|
||||||
criteriaBuilder.equal(subQueryRoot.get(TenantUserEntity._tenantId), this.tenantScope.getTenant()),
|
|
||||||
criteriaBuilder.equal(subQueryRoot.get(TenantUserEntity._userId), this.userScope.getUserId()),
|
|
||||||
criteriaBuilder.equal(subQueryRoot.get(TenantUserEntity._isActive), IsActive.Active)
|
|
||||||
);
|
|
||||||
} catch (InvalidApplicationException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
))
|
|
||||||
)
|
|
||||||
));
|
|
||||||
query.multiselect(root.get(UserEntity._id).alias(UserEntity._id));
|
|
||||||
List<UserEntity> results = this.entityManager.createQuery(query).getResultList();
|
|
||||||
return !results.isEmpty();
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void postHandle(@NonNull WebRequest request, ModelMap model) {
|
|
||||||
this.tenantScope.setTenant(null, null);
|
|
||||||
this.tenantEntityManager.disableTenantFilters();
|
|
||||||
}
|
|
||||||
@Override
|
|
||||||
public void afterCompletion(@NonNull WebRequest request, Exception ex) {
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,184 +0,0 @@
|
||||||
package gr.cite.annotation.web.scope.tenant;
|
|
||||||
|
|
||||||
|
|
||||||
import gr.cite.annotation.authorization.ClaimNames;
|
|
||||||
import gr.cite.annotation.common.enums.IsActive;
|
|
||||||
import gr.cite.annotation.common.scope.tenant.TenantScope;
|
|
||||||
import gr.cite.annotation.convention.ConventionService;
|
|
||||||
import gr.cite.annotation.data.TenantEntity;
|
|
||||||
import gr.cite.annotation.errorcode.ErrorThesaurusProperties;
|
|
||||||
import gr.cite.commons.web.oidc.principal.CurrentPrincipalResolver;
|
|
||||||
import gr.cite.commons.web.oidc.principal.MyPrincipal;
|
|
||||||
import gr.cite.commons.web.oidc.principal.extractor.ClaimExtractor;
|
|
||||||
import gr.cite.commons.web.oidc.principal.extractor.ClaimExtractorContext;
|
|
||||||
import gr.cite.tools.exception.MyForbiddenException;
|
|
||||||
import gr.cite.tools.logging.LoggerService;
|
|
||||||
import jakarta.persistence.EntityManager;
|
|
||||||
import jakarta.persistence.PersistenceContext;
|
|
||||||
import jakarta.persistence.criteria.CriteriaBuilder;
|
|
||||||
import jakarta.persistence.criteria.CriteriaQuery;
|
|
||||||
import jakarta.persistence.criteria.Root;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.lang.NonNull;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
import org.springframework.ui.ModelMap;
|
|
||||||
import org.springframework.web.context.request.WebRequest;
|
|
||||||
import org.springframework.web.context.request.WebRequestInterceptor;
|
|
||||||
|
|
||||||
import javax.management.InvalidApplicationException;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
@Component
|
|
||||||
public class TenantScopeClaimInterceptor implements WebRequestInterceptor {
|
|
||||||
private static final LoggerService logger = new LoggerService(LoggerFactory.getLogger(TenantScopeClaimInterceptor.class));
|
|
||||||
private final TenantScope tenantScope;
|
|
||||||
private final ConventionService conventionService;
|
|
||||||
private final TenantScopeProperties tenantScopeProperties;
|
|
||||||
private final ErrorThesaurusProperties errorThesaurusProperties;
|
|
||||||
private final ClaimExtractor claimExtractor;
|
|
||||||
private final CurrentPrincipalResolver currentPrincipalResolver;
|
|
||||||
private final String clientTenantClaimName;
|
|
||||||
private final ClaimExtractorContext claimExtractorContext;
|
|
||||||
private final TenantByCodeCacheService tenantByCodeCacheService;
|
|
||||||
private final TenantByIdCacheService tenantByIdCacheService;
|
|
||||||
@PersistenceContext
|
|
||||||
public EntityManager entityManager;
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
public TenantScopeClaimInterceptor(
|
|
||||||
TenantScope tenantScope,
|
|
||||||
ConventionService conventionService,
|
|
||||||
ClaimExtractor claimExtractor,
|
|
||||||
CurrentPrincipalResolver currentPrincipalResolver,
|
|
||||||
ErrorThesaurusProperties errorThesaurusProperties,
|
|
||||||
TenantScopeProperties tenantScopeProperties,
|
|
||||||
ClaimExtractorContext claimExtractorContext,
|
|
||||||
TenantByCodeCacheService tenantByCodeCacheService,
|
|
||||||
TenantByIdCacheService tenantByIdCacheService
|
|
||||||
) {
|
|
||||||
this.tenantScope = tenantScope;
|
|
||||||
this.conventionService = conventionService;
|
|
||||||
this.currentPrincipalResolver = currentPrincipalResolver;
|
|
||||||
this.claimExtractor = claimExtractor;
|
|
||||||
this.errorThesaurusProperties = errorThesaurusProperties;
|
|
||||||
this.tenantScopeProperties = tenantScopeProperties;
|
|
||||||
this.claimExtractorContext = claimExtractorContext;
|
|
||||||
this.tenantByCodeCacheService = tenantByCodeCacheService;
|
|
||||||
this.tenantByIdCacheService = tenantByIdCacheService;
|
|
||||||
this.clientTenantClaimName = this.tenantScopeProperties.getClientClaimsPrefix() + ClaimNames.TenantClaimName;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void preHandle(@NotNull WebRequest request) throws InvalidApplicationException {
|
|
||||||
if (!this.currentPrincipalResolver.currentPrincipal().isAuthenticated()) return;
|
|
||||||
if (!this.tenantScope.isMultitenant()) return;
|
|
||||||
|
|
||||||
MyPrincipal principal = this.currentPrincipalResolver.currentPrincipal();
|
|
||||||
if (principal != null && principal.isAuthenticated() /* principal.Claims.Any() */) {
|
|
||||||
boolean scoped = this.scopeByPrincipal(principal);
|
|
||||||
if (!scoped) scoped = this.scopeByClient(principal);
|
|
||||||
if (!scoped && this.tenantScope.isSet() && this.tenantScopeProperties.getEnforceTrustedTenant())
|
|
||||||
throw new MyForbiddenException(this.errorThesaurusProperties.getMissingTenant().getCode(), this.errorThesaurusProperties.getMissingTenant().getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean scopeByPrincipal(MyPrincipal principal) {
|
|
||||||
String tenantCode = this.claimExtractor.tenantString(principal);
|
|
||||||
if (this.conventionService.isNullOrEmpty(tenantCode)) tenantCode = this.claimExtractor.asString(principal, this.clientTenantClaimName);
|
|
||||||
if (tenantCode == null || this.conventionService.isNullOrEmpty(tenantCode)) return false;
|
|
||||||
|
|
||||||
if (tenantCode.equalsIgnoreCase(this.tenantScope.getDefaultTenantCode())){
|
|
||||||
logger.debug("parsed tenant header and set tenant to default tenant");
|
|
||||||
this.tenantScope.setTenant(null, tenantCode);
|
|
||||||
this.claimExtractorContext.putReplaceParameter(TenantScope.TenantReplaceParameter, tenantCode);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
UUID tenantId = this.conventionService.parseUUIDSafe(tenantCode);
|
|
||||||
if (tenantId == null) {
|
|
||||||
TenantByCodeCacheService.TenantByCodeCacheValue cacheValue = this.tenantByCodeCacheService.lookup(this.tenantByCodeCacheService.buildKey(tenantCode));
|
|
||||||
if (cacheValue != null) {
|
|
||||||
tenantId = cacheValue.getTenantId();
|
|
||||||
} else {
|
|
||||||
tenantId = this.getTenantIdFromDatabase(tenantCode);
|
|
||||||
this.tenantByCodeCacheService.put(new TenantByCodeCacheService.TenantByCodeCacheValue(tenantCode, tenantId));
|
|
||||||
this.tenantByIdCacheService.put(new TenantByIdCacheService.TenantByIdCacheValue(tenantCode, tenantId));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
logger.debug("tenant claim was set to {}", tenantId);
|
|
||||||
TenantByIdCacheService.TenantByIdCacheValue cacheValue = this.tenantByIdCacheService.lookup(this.tenantByIdCacheService.buildKey(tenantId));
|
|
||||||
|
|
||||||
if (cacheValue != null) {
|
|
||||||
tenantCode = cacheValue.getTenantCode();
|
|
||||||
} else {
|
|
||||||
tenantCode = this.getTenantCodeFromDatabase(tenantId);
|
|
||||||
this.tenantByCodeCacheService.put(new TenantByCodeCacheService.TenantByCodeCacheValue(tenantCode, tenantId));
|
|
||||||
this.tenantByIdCacheService.put(new TenantByIdCacheService.TenantByIdCacheValue(tenantCode, tenantId));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tenantId != null) {
|
|
||||||
logger.debug("parsed tenant header and set tenant id to {}", tenantId);
|
|
||||||
this.tenantScope.setTenant(tenantId, tenantCode);
|
|
||||||
this.claimExtractorContext.putReplaceParameter(TenantScope.TenantReplaceParameter, tenantCode);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean scopeByClient(MyPrincipal principal) throws InvalidApplicationException {
|
|
||||||
String client = this.claimExtractor.client(principal);
|
|
||||||
|
|
||||||
Boolean isWhiteListed = this.tenantScopeProperties.getWhiteListedClients() != null && !this.conventionService.isNullOrEmpty(client) && this.tenantScopeProperties.getWhiteListedClients().contains(client);
|
|
||||||
logger.debug("client is whitelisted : {}, scope is set: {}, with value {}", isWhiteListed, this.tenantScope.isSet(), (this.tenantScope.isSet() ? this.tenantScope.getTenant() : null));
|
|
||||||
|
|
||||||
return isWhiteListed && this.tenantScope.isSet();
|
|
||||||
}
|
|
||||||
|
|
||||||
private UUID getTenantIdFromDatabase(String tenantCode) {
|
|
||||||
CriteriaBuilder criteriaBuilder = this.entityManager.getCriteriaBuilder();
|
|
||||||
CriteriaQuery<TenantEntity> query = criteriaBuilder.createQuery(TenantEntity.class);
|
|
||||||
Root<TenantEntity> root = query.from(TenantEntity.class);
|
|
||||||
query = query.where(
|
|
||||||
criteriaBuilder.and(
|
|
||||||
criteriaBuilder.equal(root.get(TenantEntity._code), tenantCode),
|
|
||||||
criteriaBuilder.equal(root.get(TenantEntity._isActive), IsActive.Active)
|
|
||||||
)
|
|
||||||
).multiselect(root.get(TenantEntity._id).alias(TenantEntity._id));
|
|
||||||
List<TenantEntity> results = this.entityManager.createQuery(query).getResultList();
|
|
||||||
if (results.size() == 1) {
|
|
||||||
return results.getFirst().getId();
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private String getTenantCodeFromDatabase(UUID tenantId) {
|
|
||||||
CriteriaBuilder criteriaBuilder = this.entityManager.getCriteriaBuilder();
|
|
||||||
CriteriaQuery<TenantEntity> query = criteriaBuilder.createQuery(TenantEntity.class);
|
|
||||||
Root<TenantEntity> root = query.from(TenantEntity.class);
|
|
||||||
query = query.where(
|
|
||||||
criteriaBuilder.and(
|
|
||||||
criteriaBuilder.equal(root.get(TenantEntity._id), tenantId),
|
|
||||||
criteriaBuilder.equal(root.get(TenantEntity._isActive), IsActive.Active)
|
|
||||||
)
|
|
||||||
).multiselect(root.get(TenantEntity._code).alias(TenantEntity._code));
|
|
||||||
List<TenantEntity> results = this.entityManager.createQuery(query).getResultList();
|
|
||||||
if (results.size() == 1) {
|
|
||||||
return results.getFirst().getCode();
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void postHandle(@NonNull WebRequest request, ModelMap model) {
|
|
||||||
this.tenantScope.setTenant(null, null);
|
|
||||||
this.claimExtractorContext.removeReplaceParameter(TenantScope.TenantReplaceParameter);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void afterCompletion(@NonNull WebRequest request, Exception ex) {
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,9 +0,0 @@
|
||||||
package gr.cite.annotation.web.scope.tenant;
|
|
||||||
|
|
||||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
|
||||||
import org.springframework.context.annotation.Configuration;
|
|
||||||
|
|
||||||
@Configuration
|
|
||||||
@EnableConfigurationProperties(TenantScopeProperties.class)
|
|
||||||
public class TenantScopeConfiguration {
|
|
||||||
}
|
|
|
@ -1,146 +0,0 @@
|
||||||
package gr.cite.annotation.web.scope.tenant;
|
|
||||||
|
|
||||||
|
|
||||||
import gr.cite.annotation.authorization.ClaimNames;
|
|
||||||
import gr.cite.annotation.common.enums.IsActive;
|
|
||||||
import gr.cite.annotation.common.scope.tenant.TenantScope;
|
|
||||||
import gr.cite.annotation.convention.ConventionService;
|
|
||||||
import gr.cite.annotation.data.TenantEntity;
|
|
||||||
import gr.cite.commons.web.oidc.principal.CurrentPrincipalResolver;
|
|
||||||
import gr.cite.commons.web.oidc.principal.extractor.ClaimExtractorContext;
|
|
||||||
import gr.cite.tools.logging.LoggerService;
|
|
||||||
import jakarta.persistence.EntityManager;
|
|
||||||
import jakarta.persistence.PersistenceContext;
|
|
||||||
import jakarta.persistence.criteria.CriteriaBuilder;
|
|
||||||
import jakarta.persistence.criteria.CriteriaQuery;
|
|
||||||
import jakarta.persistence.criteria.Root;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.lang.NonNull;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
import org.springframework.ui.ModelMap;
|
|
||||||
import org.springframework.web.context.request.WebRequest;
|
|
||||||
import org.springframework.web.context.request.WebRequestInterceptor;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
@Component
|
|
||||||
public class TenantScopeHeaderInterceptor implements WebRequestInterceptor {
|
|
||||||
private static final LoggerService logger = new LoggerService(LoggerFactory.getLogger(TenantScopeHeaderInterceptor.class));
|
|
||||||
private final TenantScope tenantScope;
|
|
||||||
private final ConventionService conventionService;
|
|
||||||
private final TenantByCodeCacheService tenantByCodeCacheService;
|
|
||||||
private final TenantByIdCacheService tenantByIdCacheService;
|
|
||||||
private final ClaimExtractorContext claimExtractorContext;
|
|
||||||
private final CurrentPrincipalResolver currentPrincipalResolver;
|
|
||||||
@PersistenceContext
|
|
||||||
public EntityManager entityManager;
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
public TenantScopeHeaderInterceptor(
|
|
||||||
TenantScope tenantScope,
|
|
||||||
ConventionService conventionService,
|
|
||||||
TenantByCodeCacheService tenantByCodeCacheService,
|
|
||||||
TenantByIdCacheService tenantByIdCacheService,
|
|
||||||
ClaimExtractorContext claimExtractorContext,
|
|
||||||
CurrentPrincipalResolver currentPrincipalResolver
|
|
||||||
) {
|
|
||||||
this.tenantScope = tenantScope;
|
|
||||||
this.conventionService = conventionService;
|
|
||||||
this.tenantByCodeCacheService = tenantByCodeCacheService;
|
|
||||||
this.tenantByIdCacheService = tenantByIdCacheService;
|
|
||||||
this.claimExtractorContext = claimExtractorContext;
|
|
||||||
this.currentPrincipalResolver = currentPrincipalResolver;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void preHandle(@NotNull WebRequest request) {
|
|
||||||
if (!this.currentPrincipalResolver.currentPrincipal().isAuthenticated()) return;
|
|
||||||
if (!this.tenantScope.isMultitenant()) return;
|
|
||||||
|
|
||||||
String tenantCode = request.getHeader(ClaimNames.TenantClaimName);
|
|
||||||
logger.debug("retrieved request tenant header is: {}", tenantCode);
|
|
||||||
if (tenantCode == null || this.conventionService.isNullOrEmpty(tenantCode)) return;
|
|
||||||
|
|
||||||
if (tenantCode.equalsIgnoreCase(this.tenantScope.getDefaultTenantCode())){
|
|
||||||
logger.debug("parsed tenant header and set tenant to default tenant");
|
|
||||||
this.tenantScope.setTenant(null, tenantCode);
|
|
||||||
this.claimExtractorContext.putReplaceParameter(TenantScope.TenantReplaceParameter, tenantCode);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
UUID tenantId = this.conventionService.parseUUIDSafe(tenantCode);
|
|
||||||
if (tenantId == null) {
|
|
||||||
TenantByCodeCacheService.TenantByCodeCacheValue cacheValue = this.tenantByCodeCacheService.lookup(this.tenantByCodeCacheService.buildKey(tenantCode));
|
|
||||||
if (cacheValue != null) {
|
|
||||||
tenantId = cacheValue.getTenantId();
|
|
||||||
} else {
|
|
||||||
tenantId = this.getTenantIdFromDatabase(tenantCode);
|
|
||||||
this.tenantByCodeCacheService.put(new TenantByCodeCacheService.TenantByCodeCacheValue(tenantCode, tenantId));
|
|
||||||
this.tenantByIdCacheService.put(new TenantByIdCacheService.TenantByIdCacheValue(tenantCode, tenantId));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
TenantByIdCacheService.TenantByIdCacheValue cacheValue = this.tenantByIdCacheService.lookup(this.tenantByIdCacheService.buildKey(tenantId));
|
|
||||||
if (cacheValue != null) {
|
|
||||||
tenantCode = cacheValue.getTenantCode();
|
|
||||||
} else {
|
|
||||||
tenantCode = this.getTenantCodeFromDatabase(tenantId);
|
|
||||||
this.tenantByCodeCacheService.put(new TenantByCodeCacheService.TenantByCodeCacheValue(tenantCode, tenantId));
|
|
||||||
this.tenantByIdCacheService.put(new TenantByIdCacheService.TenantByIdCacheValue(tenantCode, tenantId));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tenantId != null) {
|
|
||||||
logger.debug("parsed tenant header and set tenant id to {}", tenantId);
|
|
||||||
this.tenantScope.setTenant(tenantId, tenantCode);
|
|
||||||
this.claimExtractorContext.putReplaceParameter(TenantScope.TenantReplaceParameter, tenantCode);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private UUID getTenantIdFromDatabase(String tenantCode) {
|
|
||||||
CriteriaBuilder criteriaBuilder = this.entityManager.getCriteriaBuilder();
|
|
||||||
CriteriaQuery<TenantEntity> query = criteriaBuilder.createQuery(TenantEntity.class);
|
|
||||||
Root<TenantEntity> root = query.from(TenantEntity.class);
|
|
||||||
query = query.where(
|
|
||||||
criteriaBuilder.and(
|
|
||||||
criteriaBuilder.equal(root.get(TenantEntity._code), tenantCode),
|
|
||||||
criteriaBuilder.equal(root.get(TenantEntity._isActive), IsActive.Active)
|
|
||||||
)
|
|
||||||
).multiselect(root.get(TenantEntity._id).alias(TenantEntity._id));
|
|
||||||
List<TenantEntity> results = this.entityManager.createQuery(query).getResultList();
|
|
||||||
if (results.size() == 1) {
|
|
||||||
return results.getFirst().getId();
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private String getTenantCodeFromDatabase(UUID tenantId) {
|
|
||||||
CriteriaBuilder criteriaBuilder = this.entityManager.getCriteriaBuilder();
|
|
||||||
CriteriaQuery<TenantEntity> query = criteriaBuilder.createQuery(TenantEntity.class);
|
|
||||||
Root<TenantEntity> root = query.from(TenantEntity.class);
|
|
||||||
query = query.where(
|
|
||||||
criteriaBuilder.and(
|
|
||||||
criteriaBuilder.equal(root.get(TenantEntity._id), tenantId),
|
|
||||||
criteriaBuilder.equal(root.get(TenantEntity._isActive), IsActive.Active)
|
|
||||||
)
|
|
||||||
).multiselect(root.get(TenantEntity._code).alias(TenantEntity._code));
|
|
||||||
List<TenantEntity> results = this.entityManager.createQuery(query).getResultList();
|
|
||||||
if (results.size() == 1) {
|
|
||||||
return results.getFirst().getCode();
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void postHandle(@NonNull WebRequest request, ModelMap model) {
|
|
||||||
|
|
||||||
this.tenantScope.setTenant(null, null);
|
|
||||||
this.claimExtractorContext.removeReplaceParameter(TenantScope.TenantReplaceParameter);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void afterCompletion(@NonNull WebRequest request, Exception ex) {
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,44 +0,0 @@
|
||||||
package gr.cite.annotation.web.scope.tenant;
|
|
||||||
|
|
||||||
|
|
||||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
|
||||||
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
@ConfigurationProperties(prefix = "tenant.interceptor")
|
|
||||||
public class TenantScopeProperties {
|
|
||||||
|
|
||||||
private String clientClaimsPrefix;
|
|
||||||
public String getClientClaimsPrefix() {
|
|
||||||
return clientClaimsPrefix;
|
|
||||||
}
|
|
||||||
public void setClientClaimsPrefix(String clientClaimsPrefix) {
|
|
||||||
this.clientClaimsPrefix = clientClaimsPrefix;
|
|
||||||
}
|
|
||||||
|
|
||||||
private HashSet<String> whiteListedClients;
|
|
||||||
public HashSet<String> getWhiteListedClients() {
|
|
||||||
return whiteListedClients;
|
|
||||||
}
|
|
||||||
public void setWhiteListedClients(HashSet<String> whiteListedClients) {
|
|
||||||
this.whiteListedClients = whiteListedClients;
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<String> whiteListedEndpoints;
|
|
||||||
public List<String> getWhiteListedEndpoints() {
|
|
||||||
return whiteListedEndpoints;
|
|
||||||
}
|
|
||||||
public void setWhiteListedEndpoints(List<String> whiteListedEndpoints) {
|
|
||||||
this.whiteListedEndpoints = whiteListedEndpoints;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Boolean enforceTrustedTenant;
|
|
||||||
public Boolean getEnforceTrustedTenant() {
|
|
||||||
return enforceTrustedTenant;
|
|
||||||
}
|
|
||||||
public void setEnforceTrustedTenant(Boolean enforceTrustedTenant) {
|
|
||||||
this.enforceTrustedTenant = enforceTrustedTenant;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,12 +0,0 @@
|
||||||
package gr.cite.annotation.web.scope.tenant;
|
|
||||||
|
|
||||||
import gr.cite.tools.cache.CacheOptions;
|
|
||||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
|
||||||
import org.springframework.context.annotation.Configuration;
|
|
||||||
|
|
||||||
@Configuration
|
|
||||||
@ConfigurationProperties(prefix = "cache.user-allowed-tenant")
|
|
||||||
public class UserAllowedTenantCacheOptions extends CacheOptions {
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
|
@ -1,91 +0,0 @@
|
||||||
package gr.cite.annotation.web.scope.tenant;
|
|
||||||
|
|
||||||
import gr.cite.annotation.event.UserAddedToTenantEvent;
|
|
||||||
import gr.cite.annotation.event.UserRemovedFromTenantEvent;
|
|
||||||
import gr.cite.tools.cache.CacheService;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.context.event.EventListener;
|
|
||||||
import org.springframework.stereotype.Service;
|
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Locale;
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
@Service
|
|
||||||
public class UserAllowedTenantCacheService extends CacheService<UserAllowedTenantCacheService.UserAllowedTenantCacheValue> {
|
|
||||||
|
|
||||||
public static class UserAllowedTenantCacheValue {
|
|
||||||
|
|
||||||
public UserAllowedTenantCacheValue() {
|
|
||||||
}
|
|
||||||
|
|
||||||
public UserAllowedTenantCacheValue(UUID userId, UUID tenantId, boolean isAllowed) {
|
|
||||||
this.userId = userId;
|
|
||||||
this.tenantId = tenantId;
|
|
||||||
this.isAllowed = isAllowed;
|
|
||||||
}
|
|
||||||
|
|
||||||
private UUID userId;
|
|
||||||
|
|
||||||
public UUID getUserId() {
|
|
||||||
return userId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setUserId(UUID userId) {
|
|
||||||
this.userId = userId;
|
|
||||||
}
|
|
||||||
|
|
||||||
private UUID tenantId;
|
|
||||||
|
|
||||||
public UUID getTenantId() {
|
|
||||||
return tenantId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setTenantId(UUID tenantId) {
|
|
||||||
this.tenantId = tenantId;
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isAllowed;
|
|
||||||
|
|
||||||
public boolean isAllowed() {
|
|
||||||
return isAllowed;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setAllowed(boolean allowed) {
|
|
||||||
isAllowed = allowed;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
public UserAllowedTenantCacheService(UserAllowedTenantCacheOptions options) {
|
|
||||||
super(options);
|
|
||||||
}
|
|
||||||
|
|
||||||
@EventListener
|
|
||||||
public void handleUserRemovedFromTenantEvent(UserRemovedFromTenantEvent event) {
|
|
||||||
this.evict(this.buildKey(event.getUserId(), event.getTenantId()));
|
|
||||||
}
|
|
||||||
|
|
||||||
@EventListener
|
|
||||||
public void handleUserAddedToTenantEvent(UserAddedToTenantEvent event) {
|
|
||||||
this.evict(this.buildKey(event.getUserId(), event.getTenantId()));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Class<UserAllowedTenantCacheValue> valueClass() {
|
|
||||||
return UserAllowedTenantCacheValue.class;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String keyOf(UserAllowedTenantCacheValue value) {
|
|
||||||
return this.buildKey(value.getUserId(), value.getTenantId());
|
|
||||||
}
|
|
||||||
|
|
||||||
public String buildKey(UUID userId, UUID tenantId) {
|
|
||||||
HashMap<String, String> keyParts = new HashMap<>();
|
|
||||||
keyParts.put("$user_id$", userId.toString().toLowerCase(Locale.ROOT));
|
|
||||||
keyParts.put("$tenant_id$", tenantId.toString().toLowerCase(Locale.ROOT));
|
|
||||||
return this.generateKey(keyParts);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,81 +0,0 @@
|
||||||
package gr.cite.annotation.web.scope.user;
|
|
||||||
|
|
||||||
|
|
||||||
import gr.cite.annotation.common.scope.user.UserScope;
|
|
||||||
import gr.cite.annotation.data.UserCredentialEntity;
|
|
||||||
import gr.cite.annotation.model.UserCredential;
|
|
||||||
import gr.cite.annotation.query.UserCredentialQuery;
|
|
||||||
import gr.cite.commons.web.oidc.principal.CurrentPrincipalResolver;
|
|
||||||
import gr.cite.commons.web.oidc.principal.extractor.ClaimExtractor;
|
|
||||||
import gr.cite.tools.data.query.QueryFactory;
|
|
||||||
import gr.cite.tools.exception.MyForbiddenException;
|
|
||||||
import gr.cite.tools.fieldset.BaseFieldSet;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.lang.NonNull;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
import org.springframework.ui.ModelMap;
|
|
||||||
import org.springframework.web.context.request.WebRequest;
|
|
||||||
import org.springframework.web.context.request.WebRequestInterceptor;
|
|
||||||
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
@Component
|
|
||||||
public class UserInterceptor implements WebRequestInterceptor {
|
|
||||||
private final UserScope userScope;
|
|
||||||
private final ClaimExtractor claimExtractor;
|
|
||||||
private final CurrentPrincipalResolver currentPrincipalResolver;
|
|
||||||
private final UserInterceptorCacheService userInterceptorCacheService;
|
|
||||||
private final QueryFactory queryFactory;
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
public UserInterceptor(
|
|
||||||
UserScope userScope,
|
|
||||||
ClaimExtractor claimExtractor,
|
|
||||||
CurrentPrincipalResolver currentPrincipalResolver,
|
|
||||||
UserInterceptorCacheService userInterceptorCacheService,
|
|
||||||
QueryFactory queryFactory) {
|
|
||||||
this.userScope = userScope;
|
|
||||||
this.currentPrincipalResolver = currentPrincipalResolver;
|
|
||||||
this.claimExtractor = claimExtractor;
|
|
||||||
this.userInterceptorCacheService = userInterceptorCacheService;
|
|
||||||
this.queryFactory = queryFactory;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void preHandle(@NotNull WebRequest request) {
|
|
||||||
UUID userId = null;
|
|
||||||
if (this.currentPrincipalResolver.currentPrincipal().isAuthenticated()) {
|
|
||||||
String subjectId = this.claimExtractor.subjectString(this.currentPrincipalResolver.currentPrincipal());
|
|
||||||
if (subjectId == null || subjectId.isBlank()) throw new MyForbiddenException("Empty subjects not allowed");
|
|
||||||
|
|
||||||
UserInterceptorCacheService.UserInterceptorCacheValue cacheValue = this.userInterceptorCacheService.lookup(this.userInterceptorCacheService.buildKey(subjectId));
|
|
||||||
if (cacheValue != null) {
|
|
||||||
userId = cacheValue.getUserId();
|
|
||||||
} else {
|
|
||||||
userId = this.findExistingUserFromDb(subjectId);
|
|
||||||
if (userId != null) {
|
|
||||||
cacheValue = new UserInterceptorCacheService.UserInterceptorCacheValue(subjectId, userId);
|
|
||||||
this.userInterceptorCacheService.put(cacheValue);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.userScope.setUserId(userId);
|
|
||||||
}
|
|
||||||
private UUID findExistingUserFromDb(String subjectId) {
|
|
||||||
UserCredentialEntity userCredential = this.queryFactory.query(UserCredentialQuery.class).disableTracking().externalIds(subjectId).firstAs(new BaseFieldSet().ensure(UserCredential._user));
|
|
||||||
if (userCredential != null) {
|
|
||||||
return userCredential.getUserId();
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
@Override
|
|
||||||
public void postHandle(@NonNull WebRequest request, ModelMap model) {
|
|
||||||
this.userScope.setUserId(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void afterCompletion(@NonNull WebRequest request, Exception ex) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,10 +0,0 @@
|
||||||
package gr.cite.annotation.web.scope.user;
|
|
||||||
|
|
||||||
import gr.cite.tools.cache.CacheOptions;
|
|
||||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
|
||||||
import org.springframework.context.annotation.Configuration;
|
|
||||||
|
|
||||||
@Configuration
|
|
||||||
@ConfigurationProperties(prefix = "cache.user-by-subject-id")
|
|
||||||
public class UserInterceptorCacheOptions extends CacheOptions {
|
|
||||||
}
|
|
|
@ -1,77 +0,0 @@
|
||||||
package gr.cite.annotation.web.scope.user;
|
|
||||||
|
|
||||||
import gr.cite.annotation.convention.ConventionService;
|
|
||||||
import gr.cite.annotation.event.UserCredentialTouchedEvent;
|
|
||||||
import gr.cite.tools.cache.CacheService;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.context.event.EventListener;
|
|
||||||
import org.springframework.stereotype.Service;
|
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
@Service
|
|
||||||
public class UserInterceptorCacheService extends CacheService<UserInterceptorCacheService.UserInterceptorCacheValue> {
|
|
||||||
private final ConventionService conventionService;
|
|
||||||
|
|
||||||
public static class UserInterceptorCacheValue {
|
|
||||||
|
|
||||||
public UserInterceptorCacheValue() {
|
|
||||||
}
|
|
||||||
|
|
||||||
public UserInterceptorCacheValue(String subjectId, UUID userId) {
|
|
||||||
this.subjectId = subjectId;
|
|
||||||
this.userId = userId;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public String getSubjectId() {
|
|
||||||
return subjectId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setSubjectId(String subjectId) {
|
|
||||||
this.subjectId = subjectId;
|
|
||||||
}
|
|
||||||
|
|
||||||
private String subjectId;
|
|
||||||
private UUID userId;
|
|
||||||
|
|
||||||
public UUID getUserId() {
|
|
||||||
return userId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setUserId(UUID userId) {
|
|
||||||
this.userId = userId;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@EventListener
|
|
||||||
public void handleTenantTouchedEvent(UserCredentialTouchedEvent event) {
|
|
||||||
if (!this.conventionService.isNullOrEmpty(event.getSubjectId()))
|
|
||||||
this.evict(this.buildKey(event.getSubjectId()));
|
|
||||||
}
|
|
||||||
@Autowired
|
|
||||||
public UserInterceptorCacheService(UserInterceptorCacheOptions options, ConventionService conventionService){
|
|
||||||
super(options);
|
|
||||||
this.conventionService = conventionService;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Class<UserInterceptorCacheValue> valueClass() {
|
|
||||||
return UserInterceptorCacheValue.class;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String keyOf(UserInterceptorCacheValue value) {
|
|
||||||
return this.buildKey(value.getSubjectId());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public String buildKey(String subject) {
|
|
||||||
HashMap<String, String> keyParts = new HashMap<>();
|
|
||||||
keyParts.put("$subject$", subject);
|
|
||||||
return this.generateKey(keyParts);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,18 +0,0 @@
|
||||||
spring:
|
|
||||||
jackson:
|
|
||||||
default-property-inclusion: non_null
|
|
||||||
config:
|
|
||||||
import: optional:classpath:config/app.env[.properties], optional:file:../config/app.env[.properties],
|
|
||||||
optional:classpath:config/db.yml[.yml], optional:classpath:config/db-${spring.profiles.active}.yml[.yml], optional:file:../config/db-${spring.profiles.active}.yml[.yml],
|
|
||||||
optional:classpath:config/permissions.yml[.yml], optional:classpath:config/permissions-${spring.profiles.active}.yml[.yml], optional:file:../config/permissions-${spring.profiles.active}.yml[.yml],
|
|
||||||
optional:classpath:config/errors.yml[.yml], optional:classpath:config/errors-${spring.profiles.active}.yml[.yml], optional:file:../config/errors-${spring.profiles.active}.yml[.yml],
|
|
||||||
optional:classpath:config/security.yml[.yml], optional:classpath:config/security-${spring.profiles.active}.yml[.yml], optional:file:../config/security-${spring.profiles.active}.yml[.yml],
|
|
||||||
optional:classpath:config/server.yml[.yml], optional:classpath:config/server-${spring.profiles.active}.yml[.yml], optional:file:../config/server-${spring.profiles.active}.yml[.yml],
|
|
||||||
optional:classpath:config/logging.yml[.yml], optional:classpath:config/logging-${spring.profiles.active}.yml[.yml], optional:file:../config/logging-${spring.profiles.active}.yml[.yml],
|
|
||||||
optional:classpath:config/idpclaims.yml[.yml], optional:classpath:config/idpclaims-${spring.profiles.active}.yml[.yml], optional:file:../config/idpclaims-${spring.profiles.active}.yml[.yml],
|
|
||||||
optional:classpath:config/cache.yml[.yml], optional:classpath:config/cache-${spring.profiles.active}.yml[.yml], optional:file:../config/cache-${spring.profiles.active}.yml[.yml],
|
|
||||||
optional:classpath:config/tenant.yml[.yml], optional:classpath:config/tenant-${spring.profiles.active}.yml[.yml], optional:file:../config/tenant-${spring.profiles.active}.yml[.yml],
|
|
||||||
optional:classpath:config/locale.yml[.yml], optional:classpath:config/locale-${spring.profiles.active}.yml[.yml], optional:file:../config/locale-${spring.profiles.active}.yml[.yml],
|
|
||||||
optional:classpath:config/cors.yml[.yml], optional:classpath:config/cors-${spring.profiles.active}.yml[.yml], optional:file:../config/cors-${spring.profiles.active}.yml[.yml],
|
|
||||||
optional:classpath:config/queue.yml[.yml], optional:classpath:config/queue-${spring.profiles.active}.yml[.yml], optional:file:../config/queue-${spring.profiles.active}.yml[.yml],
|
|
||||||
optional:classpath:config/cipher.yml[.yml], optional:classpath:config/cipher-${spring.profiles.active}.yml[.yml], optional:file:../config/cipher-${spring.profiles.active}.yml[.yml]
|
|
|
@ -1,59 +0,0 @@
|
||||||
cache:
|
|
||||||
manager:
|
|
||||||
fallbackToNoOpCache: true
|
|
||||||
caffeineCaches:
|
|
||||||
- names: [ apikey ]
|
|
||||||
allowNullValues: true
|
|
||||||
initialCapacity: 100
|
|
||||||
maximumSize: 500
|
|
||||||
enableRecordStats: false
|
|
||||||
expireAfterWriteSeconds: 600
|
|
||||||
- names: [ tenantByCode ]
|
|
||||||
allowNullValues: true
|
|
||||||
initialCapacity: 100
|
|
||||||
maximumSize: 500
|
|
||||||
enableRecordStats: false
|
|
||||||
expireAfterWriteSeconds: 20
|
|
||||||
- names: [ tenantById ]
|
|
||||||
allowNullValues: true
|
|
||||||
initialCapacity: 100
|
|
||||||
maximumSize: 500
|
|
||||||
enableRecordStats: false
|
|
||||||
expireAfterWriteSeconds: 20
|
|
||||||
- names: [ userBySubjectId ]
|
|
||||||
allowNullValues: true
|
|
||||||
initialCapacity: 100
|
|
||||||
maximumSize: 500
|
|
||||||
enableRecordStats: false
|
|
||||||
expireAfterWriteSeconds: 20
|
|
||||||
- names: [ userAccessTenant ]
|
|
||||||
allowNullValues: true
|
|
||||||
initialCapacity: 100
|
|
||||||
maximumSize: 500
|
|
||||||
enableRecordStats: false
|
|
||||||
expireAfterWriteSeconds: 20
|
|
||||||
- names: [ "affiliation" ]
|
|
||||||
allowNullValues: true
|
|
||||||
initialCapacity: 100
|
|
||||||
maximumSize: 5000
|
|
||||||
enableRecordStats: false
|
|
||||||
expireAfterWriteSeconds: 20
|
|
||||||
mapCaches:
|
|
||||||
apiKey:
|
|
||||||
name: apikey
|
|
||||||
keyPattern: ant_resolve_$keyhash$:v0
|
|
||||||
userBySubjectId:
|
|
||||||
name: userBySubjectId
|
|
||||||
keyPattern: ant_user_by_subject_$subject$:v0
|
|
||||||
tenantByCode:
|
|
||||||
name: tenantByCode
|
|
||||||
keyPattern: ant_tenant_by_code_$code$:v0
|
|
||||||
tenantById:
|
|
||||||
name: tenantById
|
|
||||||
keyPattern: ant_tenant_by_id_$tenantId$:v0
|
|
||||||
userAllowedTenant:
|
|
||||||
name: userAccessTenant
|
|
||||||
keyPattern: ant_user_access_tenant_$user_id$_$tenant_id$:v0
|
|
||||||
affiliation:
|
|
||||||
name: affiliation
|
|
||||||
keyPattern: ant_affiliation_$entity$_$user$_$type$:v0
|
|
|
@ -1,35 +0,0 @@
|
||||||
cipher-profiles:
|
|
||||||
profile-map:
|
|
||||||
configuration-profile-name: "configuration"
|
|
||||||
queue-profile-name: "queue"
|
|
||||||
notification-profile-name: "queue"
|
|
||||||
|
|
||||||
cipher:
|
|
||||||
# salted-hash:
|
|
||||||
# default-o: null
|
|
||||||
# options: null
|
|
||||||
symetric-encryption:
|
|
||||||
default-o: null
|
|
||||||
options:
|
|
||||||
configuration:
|
|
||||||
aes:
|
|
||||||
key: ${CIPHER_SYMETRIC_ENCRYPTION_CONFIGURATION_AES_KEY:}
|
|
||||||
iv: ${CIPHER_SYMETRIC_ENCRYPTION_CONFIGURATION_AES_IV:}
|
|
||||||
queue:
|
|
||||||
aes:
|
|
||||||
key: ${CIPHER_SYMETRIC_ENCRYPTION_QUEUE_AES_KEY:}
|
|
||||||
iv: ${CIPHER_SYMETRIC_ENCRYPTION_QUEUE_AES_IV:}
|
|
||||||
masking:
|
|
||||||
default: null
|
|
||||||
options:
|
|
||||||
configuration:
|
|
||||||
character: "*"
|
|
||||||
clear-begining: 2
|
|
||||||
clear-ending: 4
|
|
||||||
at-least-percentage: 70
|
|
||||||
digital-signature:
|
|
||||||
default: null
|
|
||||||
options:
|
|
||||||
configuration:
|
|
||||||
certificate-path: null
|
|
||||||
certificate-password: null
|
|
|
@ -1,3 +0,0 @@
|
||||||
web:
|
|
||||||
cors:
|
|
||||||
allowed-origins: [ http://localhost, http://localhost:4200 ]
|
|
|
@ -1,7 +0,0 @@
|
||||||
web:
|
|
||||||
cors:
|
|
||||||
enabled: true
|
|
||||||
allowed-methods: [ HEAD, GET, POST, PUT, DELETE, PATCH ]
|
|
||||||
allowed-headers: [ Authorization, Cache-Control, Content-Type, Content-Disposition, x-tenant ]
|
|
||||||
exposed-headers: [ Authorization, Cache-Control, Content-Type, Content-Disposition ]
|
|
||||||
allow-credentials: false
|
|
|
@ -1,10 +0,0 @@
|
||||||
spring:
|
|
||||||
datasource:
|
|
||||||
maxIdle: 10
|
|
||||||
minIdle: 5
|
|
||||||
maxActive: 10
|
|
||||||
jpa:
|
|
||||||
show-sql: true
|
|
||||||
properties:
|
|
||||||
hibernate:
|
|
||||||
format_sql: false
|
|
|
@ -1,28 +0,0 @@
|
||||||
spring:
|
|
||||||
jpa:
|
|
||||||
properties:
|
|
||||||
org:
|
|
||||||
hibernate:
|
|
||||||
flushMode: MANUAL
|
|
||||||
hibernate:
|
|
||||||
globally_quoted_identifiers: true
|
|
||||||
ddl-auto: validate
|
|
||||||
dialect: org.hibernate.dialect.PostgreSQLDialect
|
|
||||||
hibernate:
|
|
||||||
naming:
|
|
||||||
physical-strategy: gr.cite.annotation.data.namingstrategy.PrefixPhysicalNamingStrategy
|
|
||||||
implicit-strategy: org.springframework.boot.orm.jpa.hibernate.SpringImplicitNamingStrategy
|
|
||||||
datasource:
|
|
||||||
url: ${DB_CONNECTION_STRING}
|
|
||||||
username: ${DB_USER}
|
|
||||||
password: ${DB_PASSWORD}
|
|
||||||
driver-class-name: org.postgresql.Driver
|
|
||||||
hikari:
|
|
||||||
connection-timeout: 30000
|
|
||||||
minimum-idle: 3
|
|
||||||
maximum-pool-size: 10
|
|
||||||
idle-timeout: 600000
|
|
||||||
max-lifetime: 1800000
|
|
||||||
|
|
||||||
naming-strategy:
|
|
||||||
prefix: ant_
|
|
|
@ -1,52 +0,0 @@
|
||||||
error-thesaurus:
|
|
||||||
# common errors start with 1..
|
|
||||||
hash-conflict:
|
|
||||||
code: 100
|
|
||||||
message: there is a hash conflict for the item modified. please reload to get the latest changes
|
|
||||||
forbidden:
|
|
||||||
code: 101
|
|
||||||
message: insufficient rights
|
|
||||||
system-error:
|
|
||||||
code: 102
|
|
||||||
message: an unexpected system error occurred
|
|
||||||
missing-tenant:
|
|
||||||
code: 103
|
|
||||||
message: tenant scope not provided
|
|
||||||
model-validation:
|
|
||||||
code: 106
|
|
||||||
message: validation error
|
|
||||||
tenant-not-allowed:
|
|
||||||
code: 112
|
|
||||||
message: tenant not allowed
|
|
||||||
tenant-tampering:
|
|
||||||
code: 127
|
|
||||||
message: Tenant tampering
|
|
||||||
|
|
||||||
# annotations¬ification errors start with 2..
|
|
||||||
invalid-api-key:
|
|
||||||
code: 200
|
|
||||||
message: provided APIKey not valid
|
|
||||||
stale-api-key:
|
|
||||||
code: 201
|
|
||||||
message: there was a problem authorizing you with your API key. Please try again. Contact the system administrator if the problem persists
|
|
||||||
sensitive-info:
|
|
||||||
code: 202
|
|
||||||
message: you are attempting to access sensitive information. please don't do that
|
|
||||||
non-person-principal:
|
|
||||||
code: 203
|
|
||||||
message: the operation is available only to person users
|
|
||||||
blocking-consent:
|
|
||||||
code: 204
|
|
||||||
message: user consents are not sufficient to complete the operation
|
|
||||||
single-tenant-configuration-per-type-supported:
|
|
||||||
code: 205
|
|
||||||
message: a single tenant configuration entry per config type is supported
|
|
||||||
incompatible-tenant-configuration-types:
|
|
||||||
code: 206
|
|
||||||
message: the provided tenant configuration type is incompatible
|
|
||||||
missing-totp-token:
|
|
||||||
code: 207
|
|
||||||
message: totp token not provided
|
|
||||||
overlapping-tenant-configuration-notifier-list:
|
|
||||||
code: 208
|
|
||||||
message: Overlapping Tenant Configuration Notifier List
|
|
|
@ -1,58 +0,0 @@
|
||||||
idpclient:
|
|
||||||
claims:
|
|
||||||
mapping:
|
|
||||||
Subject:
|
|
||||||
- type: sub
|
|
||||||
Name:
|
|
||||||
- type: name
|
|
||||||
Client:
|
|
||||||
- type: client_id
|
|
||||||
AuthenticationMethod:
|
|
||||||
- type: amr
|
|
||||||
NotBefore:
|
|
||||||
- type: nbf
|
|
||||||
AuthenticatedAt:
|
|
||||||
- type: auth_time
|
|
||||||
ExpiresAt:
|
|
||||||
- type: exp
|
|
||||||
Email:
|
|
||||||
- type: email
|
|
||||||
Roles:
|
|
||||||
- type: resource_access
|
|
||||||
path: dmp_web.roles
|
|
||||||
- type: tenant_roles
|
|
||||||
filterBy: "(.*):::TenantCode::"
|
|
||||||
extractByExpression: "(.*):(.*)"
|
|
||||||
extractExpressionValue: "[[g1]]"
|
|
||||||
GlobalRoles:
|
|
||||||
- type: resource_access
|
|
||||||
path: dmp_web.roles
|
|
||||||
TenantRoles:
|
|
||||||
- type: tenant_roles
|
|
||||||
filterBy: "(.*):::TenantCode::"
|
|
||||||
extractByExpression: "(.*):(.*)"
|
|
||||||
extractExpressionValue: "[[g1]]"
|
|
||||||
Scope:
|
|
||||||
- type: scope
|
|
||||||
AccessToken:
|
|
||||||
- type: x-access-token
|
|
||||||
visibility: SENSITIVE
|
|
||||||
Tenant:
|
|
||||||
- type: x-tenant
|
|
||||||
IssuedAt:
|
|
||||||
- type: iat
|
|
||||||
Issuer:
|
|
||||||
- type: iss
|
|
||||||
Audience:
|
|
||||||
- type: aud
|
|
||||||
TokenType:
|
|
||||||
- type: typ
|
|
||||||
AuthorizedParty:
|
|
||||||
- type: azp
|
|
||||||
Authorities:
|
|
||||||
- type: authorities
|
|
||||||
TenantCodes:
|
|
||||||
- type: tenant_roles
|
|
||||||
filterBy: "(.*):(.*)"
|
|
||||||
extractByExpression: "(.*):(.*)"
|
|
||||||
extractExpressionValue: "[[g2]]"
|
|
|
@ -1,4 +0,0 @@
|
||||||
locale:
|
|
||||||
timezone: UTC
|
|
||||||
language: en
|
|
||||||
culture: en-US
|
|
|
@ -1,2 +0,0 @@
|
||||||
logging:
|
|
||||||
config: classpath:logging/logback-dev.xml
|
|
|
@ -1,35 +0,0 @@
|
||||||
logging:
|
|
||||||
context:
|
|
||||||
request:
|
|
||||||
requestIdKey: req.id
|
|
||||||
requestRemoteHostKey: req.remoteHost
|
|
||||||
requestUriKey: req.requestURI
|
|
||||||
requestQueryStringKey: req.queryString
|
|
||||||
requestUrlKey : req.requestURL
|
|
||||||
requestMethodKey: req.method
|
|
||||||
requestUserAgentKey: req.userAgent
|
|
||||||
requestForwardedForKey: req.xForwardedFor
|
|
||||||
requestSchemeKey: req.scheme
|
|
||||||
requestRemoteAddressKey: req.remoteAddr
|
|
||||||
requestRemotePortKey: req.remotePort
|
|
||||||
requestRemoteUserKey: req.remoteUser
|
|
||||||
principal:
|
|
||||||
subjectKey: usr.subject
|
|
||||||
nameKey: usr.name
|
|
||||||
clientKey: usr.client
|
|
||||||
audit:
|
|
||||||
enable: true
|
|
||||||
requestRemoteHostKey: req.remoteHost
|
|
||||||
requestUriKey: req.requestURI
|
|
||||||
requestQueryStringKey: req.queryString
|
|
||||||
requestUrlKey : req.requestURL
|
|
||||||
requestMethodKey: req.method
|
|
||||||
requestUserAgentKey: req.userAgent
|
|
||||||
requestForwardedForKey: req.xForwardedFor
|
|
||||||
requestSchemeKey: req.scheme
|
|
||||||
requestRemoteAddressKey: req.remoteAddr
|
|
||||||
requestRemotePortKey: req.remotePort
|
|
||||||
requestRemoteUserKey: req.remoteUser
|
|
||||||
principalSubjectKey: usr.subject
|
|
||||||
principalNameKey: usr.name
|
|
||||||
principalClientKey: usr.client
|
|
|
@ -1,101 +0,0 @@
|
||||||
permissions:
|
|
||||||
policies:
|
|
||||||
DeferredAffiliation:
|
|
||||||
roles:
|
|
||||||
- TenantAdmin
|
|
||||||
- TenantUser
|
|
||||||
- TenantPlanManager
|
|
||||||
- TenantConfigManager
|
|
||||||
clients: [ ]
|
|
||||||
allowAnonymous: false
|
|
||||||
allowAuthenticated: false
|
|
||||||
# Tenants
|
|
||||||
BrowseTenant:
|
|
||||||
roles: [ ]
|
|
||||||
clients: [ ]
|
|
||||||
allowAnonymous: false
|
|
||||||
allowAuthenticated: false
|
|
||||||
EditTenant:
|
|
||||||
roles: [ ]
|
|
||||||
clients: [ "opencdmp-api-dev" ]
|
|
||||||
allowAnonymous: false
|
|
||||||
allowAuthenticated: false
|
|
||||||
DeleteTenant:
|
|
||||||
roles: [ ]
|
|
||||||
claims: [ ]
|
|
||||||
clients: [ "opencdmp-api-dev" ]
|
|
||||||
allowAnonymous: false
|
|
||||||
allowAuthenticated: false
|
|
||||||
AllowNoTenant:
|
|
||||||
roles:
|
|
||||||
- Admin
|
|
||||||
- InstallationAdmin
|
|
||||||
claims: [ ]
|
|
||||||
clients: [ ]
|
|
||||||
allowAnonymous: false
|
|
||||||
allowAuthenticated: false
|
|
||||||
# Users
|
|
||||||
BrowseUser:
|
|
||||||
roles:
|
|
||||||
- Admin
|
|
||||||
clients: [ ]
|
|
||||||
allowAnonymous: false
|
|
||||||
allowAuthenticated: false
|
|
||||||
EditUser:
|
|
||||||
roles: [ ]
|
|
||||||
clients: [ "opencdmp-api-dev" ]
|
|
||||||
allowAnonymous: false
|
|
||||||
allowAuthenticated: false
|
|
||||||
DeleteUser:
|
|
||||||
roles: [ ]
|
|
||||||
claims: [ ]
|
|
||||||
clients: [ "opencdmp-api-dev" ]
|
|
||||||
allowAnonymous: false
|
|
||||||
allowAuthenticated: false
|
|
||||||
#Annotation
|
|
||||||
BrowseAnnotation:
|
|
||||||
roles:
|
|
||||||
- Admin
|
|
||||||
- TenantAdmin
|
|
||||||
entityAffiliated: true
|
|
||||||
clients: [ ]
|
|
||||||
allowAnonymous: false
|
|
||||||
allowAuthenticated: false
|
|
||||||
NewAnnotation:
|
|
||||||
roles:
|
|
||||||
- Admin
|
|
||||||
- TenantAdmin
|
|
||||||
entityAffiliated: true
|
|
||||||
clients: [ ]
|
|
||||||
allowAnonymous: false
|
|
||||||
allowAuthenticated: false
|
|
||||||
EditAnnotation:
|
|
||||||
roles:
|
|
||||||
- Admin
|
|
||||||
- TenantAdmin
|
|
||||||
clients: [ ]
|
|
||||||
allowAnonymous: false
|
|
||||||
allowAuthenticated: false
|
|
||||||
DeleteAnnotation:
|
|
||||||
roles:
|
|
||||||
- Admin
|
|
||||||
- TenantAdmin
|
|
||||||
entityAffiliated: false
|
|
||||||
clients: [ ]
|
|
||||||
allowAnonymous: false
|
|
||||||
allowAuthenticated: false
|
|
||||||
#Tenant Configuration
|
|
||||||
BrowseTenantConfiguration:
|
|
||||||
roles:
|
|
||||||
- Admin
|
|
||||||
- TenantAdmin
|
|
||||||
clients: [ ]
|
|
||||||
allowAnonymous: false
|
|
||||||
allowAuthenticated: false
|
|
||||||
EditTenantConfiguration:
|
|
||||||
roles:
|
|
||||||
- Admin
|
|
||||||
- TenantAdmin
|
|
||||||
clients: [ ]
|
|
||||||
allowAnonymous: false
|
|
||||||
allowAuthenticated: false
|
|
|
@ -1,21 +0,0 @@
|
||||||
queue:
|
|
||||||
rabbitmq:
|
|
||||||
enable: true
|
|
||||||
durable: true
|
|
||||||
queue: cite_dmp_devel_annotation_inbox_queue
|
|
||||||
exchange: cite_dmp_devel_queue
|
|
||||||
listenerEnabled: true
|
|
||||||
publisherEnabled: true
|
|
||||||
task:
|
|
||||||
publisher:
|
|
||||||
enable: true
|
|
||||||
options:
|
|
||||||
exchange: cite_dmp_devel_queue
|
|
||||||
rabbitmq:
|
|
||||||
enable: true
|
|
||||||
listener:
|
|
||||||
enable: true
|
|
||||||
options:
|
|
||||||
exchange: cite_dmp_devel_queue
|
|
||||||
rabbitmq:
|
|
||||||
enable: true
|
|
|
@ -1,55 +0,0 @@
|
||||||
spring:
|
|
||||||
rabbitmq:
|
|
||||||
host: ${RABBIT_HOST}
|
|
||||||
port: ${RABBIT_PORT}
|
|
||||||
username: ${RABBIT_USER}
|
|
||||||
password: ${RABBIT_PASS}
|
|
||||||
ssl:
|
|
||||||
enabled: false
|
|
||||||
queue:
|
|
||||||
rabbitmq:
|
|
||||||
enable: false
|
|
||||||
appId: ${QUEUE_APP_ID}
|
|
||||||
durable: null
|
|
||||||
queue: null
|
|
||||||
exchange: null
|
|
||||||
listenerEnabled: true
|
|
||||||
publisherEnabled: true
|
|
||||||
#TODO
|
|
||||||
connection-recovery:
|
|
||||||
enable: true
|
|
||||||
network-recovery-interval: 5000
|
|
||||||
unreachable-recovery-interval: 5000
|
|
||||||
task:
|
|
||||||
publisher:
|
|
||||||
enable: false
|
|
||||||
options:
|
|
||||||
exchange: null
|
|
||||||
annotation-created-topic: annotation.created
|
|
||||||
rabbitmq:
|
|
||||||
enable: false
|
|
||||||
interval-seconds: 3
|
|
||||||
options:
|
|
||||||
retry-threashold: 100
|
|
||||||
retry-delay-step-seconds: 300
|
|
||||||
max-retry-delay-seconds: 10800
|
|
||||||
too-old-to-send-seconds: 604800
|
|
||||||
confirm-timeout-seconds: 30
|
|
||||||
listener:
|
|
||||||
enable: false
|
|
||||||
options:
|
|
||||||
exchange: null
|
|
||||||
tenant-removal-topic: tenant.remove
|
|
||||||
tenant-touch-topic: tenant.touch
|
|
||||||
user-removal-topic: user.remove
|
|
||||||
user-touch-topic: user.touch
|
|
||||||
annotation-entities-touch-topic: annotation.entities.touch
|
|
||||||
annotation-entities-removal-topic: annotation.entities.remove
|
|
||||||
rabbitmq:
|
|
||||||
enable: false
|
|
||||||
interval-seconds: 3
|
|
||||||
options:
|
|
||||||
retry-threashold: 100
|
|
||||||
retry-delay-step-seconds: 300
|
|
||||||
max-retry-delay-seconds: 10800
|
|
||||||
too-old-to-send-seconds: 604800
|
|
|
@ -1,6 +0,0 @@
|
||||||
web:
|
|
||||||
security:
|
|
||||||
idp:
|
|
||||||
resource:
|
|
||||||
jwt:
|
|
||||||
audiences: [ "dmp_annotation" ]
|
|
|
@ -1,14 +0,0 @@
|
||||||
web:
|
|
||||||
security:
|
|
||||||
enabled: true
|
|
||||||
authorized-endpoints: [ api ]
|
|
||||||
allowed-endpoints: [ public ]
|
|
||||||
idp:
|
|
||||||
api-key:
|
|
||||||
enabled: false
|
|
||||||
resource:
|
|
||||||
token-type: JWT #| opaque
|
|
||||||
jwt:
|
|
||||||
claims: [ role, x-role ]
|
|
||||||
issuer-uri: ${IDP_ISSUER_URI}
|
|
||||||
validIssuer: ${IDP_ISSUER_URI}
|
|
|
@ -1,2 +0,0 @@
|
||||||
server:
|
|
||||||
forward-headers-strategy: FRAMEWORK
|
|
|
@ -1,13 +0,0 @@
|
||||||
server:
|
|
||||||
port: ${WEB_PORT}
|
|
||||||
forward-headers-strategy: NONE
|
|
||||||
tomcat:
|
|
||||||
threads:
|
|
||||||
max: 20
|
|
||||||
max-connections: 10000
|
|
||||||
|
|
||||||
spring:
|
|
||||||
servlet:
|
|
||||||
multipart:
|
|
||||||
max-file-size: 10MB
|
|
||||||
max-request-size: 10MB
|
|
|
@ -1,7 +0,0 @@
|
||||||
tenant:
|
|
||||||
multitenancy:
|
|
||||||
is-multitenant: true
|
|
||||||
default-tenant-code: default
|
|
||||||
interceptor:
|
|
||||||
client-claims-prefix: client_
|
|
||||||
enforce-trusted-tenant: false
|
|
|
@ -1,7 +0,0 @@
|
||||||
tenant:
|
|
||||||
multitenancy:
|
|
||||||
is-multitenant: false
|
|
||||||
interceptor:
|
|
||||||
white-listed-clients: [ ]
|
|
||||||
enforce-trusted-tenant: false
|
|
||||||
white-listed-endpoints: [ '/api/annotation/principal/me' ]
|
|
|
@ -1,57 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<configuration debug="true">
|
|
||||||
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
|
||||||
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
|
|
||||||
<Pattern>%date{ISO8601} [%thread] %-5level %logger{36} [%X{req.id}] - %message%n</Pattern>
|
|
||||||
</encoder>
|
|
||||||
</appender>
|
|
||||||
|
|
||||||
<appender name="TROUBLESHOOTING" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
|
||||||
<file>logs/logging.log</file>
|
|
||||||
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
|
|
||||||
<fileNamePattern>logs/logging.%d{yyyy-MM-dd}.%i.log</fileNamePattern>
|
|
||||||
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
|
|
||||||
<maxFileSize>100MB</maxFileSize>
|
|
||||||
</timeBasedFileNamingAndTriggeringPolicy>
|
|
||||||
<maxHistory>15</maxHistory>
|
|
||||||
</rollingPolicy>
|
|
||||||
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
|
|
||||||
<Pattern>%date{ISO8601} [%thread] %-5level %logger{36} [%X{req.id}] - %message%n</Pattern>
|
|
||||||
</encoder>
|
|
||||||
</appender>
|
|
||||||
|
|
||||||
<appender name="AUDITING" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
|
||||||
<file>logs/auditing.log</file>
|
|
||||||
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
|
|
||||||
<fileNamePattern>logs/auditing.%d{yyyy-MM-dd}.%i.log</fileNamePattern>
|
|
||||||
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
|
|
||||||
<maxFileSize>100MB</maxFileSize>
|
|
||||||
</timeBasedFileNamingAndTriggeringPolicy>
|
|
||||||
<maxHistory>15</maxHistory>
|
|
||||||
</rollingPolicy>
|
|
||||||
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
|
|
||||||
<Pattern>%date{ISO8601} - %X{req.id} - %message%n</Pattern>
|
|
||||||
</encoder>
|
|
||||||
</appender>
|
|
||||||
|
|
||||||
<logger name="org.springframework.web" level="INFO" additivity="false">
|
|
||||||
<appender-ref ref="TROUBLESHOOTING"/>
|
|
||||||
<appender-ref ref="STDOUT"/>
|
|
||||||
</logger>
|
|
||||||
<logger name="org.hibernate" level="INFO" additivity="false">
|
|
||||||
<appender-ref ref="TROUBLESHOOTING"/>
|
|
||||||
<appender-ref ref="STDOUT"/>
|
|
||||||
</logger>
|
|
||||||
<logger name="gr.cite" level="DEBUG" additivity="false">
|
|
||||||
<appender-ref ref="TROUBLESHOOTING"/>
|
|
||||||
<appender-ref ref="STDOUT"/>
|
|
||||||
</logger>
|
|
||||||
<logger name="audit" level="INFO" additivity="false">
|
|
||||||
<appender-ref ref="AUDITING"/>
|
|
||||||
<appender-ref ref="STDOUT"/>
|
|
||||||
</logger>
|
|
||||||
<root level="info">
|
|
||||||
<appender-ref ref="TROUBLESHOOTING"/>
|
|
||||||
<appender-ref ref="STDOUT"/>
|
|
||||||
</root>
|
|
||||||
</configuration>
|
|
|
@ -1,10 +0,0 @@
|
||||||
validation.empty=Value cannot be empty
|
|
||||||
validation.hashempty=Hash must be set
|
|
||||||
validation.lowerthanmin=Value must be larger than {value}
|
|
||||||
validation.largerthanmax=Value must be less than {value}
|
|
||||||
validation.invalidid=Not valid id
|
|
||||||
General_ItemNotFound=Item {0} of type {1} not found
|
|
||||||
Validation_Required={0} is required
|
|
||||||
Validation_OverPosting=Too much info
|
|
||||||
Validation_MaxLength={0} too long
|
|
||||||
Validation_UnexpectedValue=Unexpected value in field {0}
|
|
|
@ -1,6 +0,0 @@
|
||||||
validation.empty=el-Value cannot be empty
|
|
||||||
validation.hashempty=el-Hash must be set
|
|
||||||
validation.lowerthanmin=el-Value must be larger than {value}
|
|
||||||
validation.largerthanmax=el-Value must be less than {value}
|
|
||||||
validation.invalidid=el-Not valid id
|
|
||||||
General_ItemNotFound=el-Item {0} of type {1} not found
|
|
|
@ -1,33 +0,0 @@
|
||||||
HELP.md
|
|
||||||
target/
|
|
||||||
!.mvn/wrapper/maven-wrapper.jar
|
|
||||||
!**/src/main/**/target/
|
|
||||||
!**/src/test/**/target/
|
|
||||||
|
|
||||||
### STS ###
|
|
||||||
.apt_generated
|
|
||||||
.classpath
|
|
||||||
.factorypath
|
|
||||||
.project
|
|
||||||
.settings
|
|
||||||
.springBeans
|
|
||||||
.sts4-cache
|
|
||||||
|
|
||||||
### IntelliJ IDEA ###
|
|
||||||
.idea
|
|
||||||
*.iws
|
|
||||||
*.iml
|
|
||||||
*.ipr
|
|
||||||
|
|
||||||
### NetBeans ###
|
|
||||||
/nbproject/private/
|
|
||||||
/nbbuild/
|
|
||||||
/dist/
|
|
||||||
/nbdist/
|
|
||||||
/.nb-gradle/
|
|
||||||
build/
|
|
||||||
!**/src/main/**/build/
|
|
||||||
!**/src/test/**/build/
|
|
||||||
|
|
||||||
### VS Code ###
|
|
||||||
.vscode/
|
|
|
@ -1,101 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
||||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
|
||||||
<modelVersion>4.0.0</modelVersion>
|
|
||||||
|
|
||||||
<parent>
|
|
||||||
<groupId>gr.cite</groupId>
|
|
||||||
<artifactId>annotation-service-parent</artifactId>
|
|
||||||
<version>${revision}</version>
|
|
||||||
<relativePath>../pom.xml</relativePath>
|
|
||||||
</parent>
|
|
||||||
|
|
||||||
<artifactId>annotation</artifactId>
|
|
||||||
<version>${revision}</version>
|
|
||||||
|
|
||||||
<properties>
|
|
||||||
<java.version>21</java.version>
|
|
||||||
<maven.compiler.source>21</maven.compiler.source>
|
|
||||||
<maven.compiler.target>21</maven.compiler.target>
|
|
||||||
<revision>1.0.0-SNAPSHOT</revision>
|
|
||||||
</properties>
|
|
||||||
|
|
||||||
<dependencies>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.springframework.boot</groupId>
|
|
||||||
<artifactId>spring-boot-starter-test</artifactId>
|
|
||||||
<scope>test</scope>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.springframework.boot</groupId>
|
|
||||||
<artifactId>spring-boot-starter-data-jpa</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.springframework.boot</groupId>
|
|
||||||
<artifactId>spring-boot-starter-validation</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.springframework.boot</groupId>
|
|
||||||
<artifactId>spring-boot-starter-mail</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.apache.poi</groupId>
|
|
||||||
<artifactId>poi</artifactId>
|
|
||||||
<version>5.2.2</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.apache.poi</groupId>
|
|
||||||
<artifactId>poi-ooxml</artifactId>
|
|
||||||
<version>5.2.2</version>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>gr.cite</groupId>
|
|
||||||
<artifactId>data-tools</artifactId>
|
|
||||||
<version>2.1.5</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>gr.cite</groupId>
|
|
||||||
<artifactId>field-set</artifactId>
|
|
||||||
<version>2.1.0</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>gr.cite</groupId>
|
|
||||||
<artifactId>oidc-authn</artifactId>
|
|
||||||
<version>2.2.2</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>gr.cite</groupId>
|
|
||||||
<artifactId>logging</artifactId>
|
|
||||||
<version>1.0.0</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>gr.cite</groupId>
|
|
||||||
<artifactId>oidc-authz</artifactId>
|
|
||||||
<version>2.1.0</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>gr.cite</groupId>
|
|
||||||
<artifactId>exceptions</artifactId>
|
|
||||||
<version>2.1.0</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>gr.cite</groupId>
|
|
||||||
<artifactId>validation</artifactId>
|
|
||||||
<version>3.0.3</version>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.fasterxml.jackson.datatype</groupId>
|
|
||||||
<artifactId>jackson-datatype-jsr310</artifactId>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>gr.cite</groupId>
|
|
||||||
<artifactId>cipher</artifactId>
|
|
||||||
<version>2.1.0</version>
|
|
||||||
<scope>compile</scope>
|
|
||||||
</dependency>
|
|
||||||
</dependencies>
|
|
||||||
|
|
||||||
</project>
|
|
|
@ -1,59 +0,0 @@
|
||||||
package gr.cite.annotation.audit;
|
|
||||||
|
|
||||||
import gr.cite.tools.logging.EventId;
|
|
||||||
|
|
||||||
public class AuditableAction {
|
|
||||||
// public static final EventId Tenant_Available_Notifiers_Query = new EventId(2006, "Tenant_Available_Notifiers_Query");
|
|
||||||
public static final EventId Principal_Lookup = new EventId(6000, "Principal_Lookup");
|
|
||||||
public static final EventId Tenants_Lookup = new EventId(6001, "Tenants_Lookup");
|
|
||||||
|
|
||||||
// public static final EventId User_Available_Notifiers_Query = new EventId(10004, "User_Available_Notifiers_Query");
|
|
||||||
|
|
||||||
public static final EventId User_Query = new EventId(11000, "User_Query");
|
|
||||||
public static final EventId User_Lookup = new EventId(11001, "User_Lookup");
|
|
||||||
public static final EventId User_Persist = new EventId(11002, "User_Persist");
|
|
||||||
public static final EventId User_Delete = new EventId(11003, "User_Delete");
|
|
||||||
|
|
||||||
public static final EventId Tenant_Query = new EventId(12000, "Tenant_Query");
|
|
||||||
public static final EventId Tenant_Lookup = new EventId(12001, "Tenant_Lookup");
|
|
||||||
public static final EventId Tenant_Persist = new EventId(12002, "Tenant_Persist");
|
|
||||||
public static final EventId Tenant_Delete = new EventId(12003, "Tenant_Delete");
|
|
||||||
|
|
||||||
// public static final EventId Notification_Query = new EventId(19000, "Notification_Query");
|
|
||||||
// public static final EventId Notification_Lookup = new EventId(19001, "Notification_Lookup");
|
|
||||||
// public static final EventId Notification_Persist = new EventId(19002, "Notification_Persist");
|
|
||||||
// public static final EventId Notification_Delete = new EventId(19003, "Notification_Delete");
|
|
||||||
|
|
||||||
// public static final EventId InApp_Notification_Query = new EventId(20000, "InApp_Notification_Query");
|
|
||||||
// public static final EventId InApp_Notification_Lookup = new EventId(20001, "InApp_Notification_Lookup");
|
|
||||||
// public static final EventId InApp_Notification_Persist = new EventId(20002, "InApp_Notification_Persist");
|
|
||||||
// public static final EventId InApp_Notification_Delete = new EventId(20003, "InApp_Notification_Delete");
|
|
||||||
// public static final EventId InApp_Notification_Read = new EventId(20003, "InApp_Notification_Read");
|
|
||||||
// public static final EventId InApp_Notification_Read_All = new EventId(20003, "InApp_Notification_Read_All");
|
|
||||||
|
|
||||||
public static final EventId Tenant_Configuration_Query = new EventId(21000, "Tenant_Configuration_Query");
|
|
||||||
public static final EventId Tenant_Configuration_Lookup = new EventId(21001, "Tenant_Configuration_Lookup");
|
|
||||||
public static final EventId Tenant_Configuration_Persist = new EventId(21002, "Tenant_Configuration_Persist");
|
|
||||||
public static final EventId Tenant_Configuration_Delete = new EventId(21003, "Tenant_Configuration_Delete");
|
|
||||||
|
|
||||||
// public static final EventId User_Notification_Preference_Query = new EventId(22000, "User_Notification_Preference_Query");
|
|
||||||
// public static final EventId User_Notification_Preference_Lookup = new EventId(22001, "User_Notification_Preference_Lookup");
|
|
||||||
// public static final EventId User_Notification_Preference_Persist = new EventId(22002, "User_Notification_Preference_Persist");
|
|
||||||
// public static final EventId User_Notification_Preference_Delete = new EventId(22003, "User_Notification_Preference_Delete");
|
|
||||||
//
|
|
||||||
// public static final EventId Notification_Template_Query = new EventId(23000, "Notification_Template_Query");
|
|
||||||
// public static final EventId Notification_Template_Lookup = new EventId(23001, "Notification_Template_Lookup");
|
|
||||||
// public static final EventId Notification_Template_Persist = new EventId(23002, "Notification_Template_Persist");
|
|
||||||
// public static final EventId Notification_Template_Delete = new EventId(23003, "Notification_Template_Delete");
|
|
||||||
|
|
||||||
public static final EventId Annotation_Query = new EventId(24000, "Annotation_Query");
|
|
||||||
public static final EventId Annotation_Lookup = new EventId(24001, "Annotation_Lookup");
|
|
||||||
public static final EventId Annotation_Persist = new EventId(24002, "Annotation_Persist");
|
|
||||||
public static final EventId Annotation_Delete = new EventId(24003, "Annotation_Delete");
|
|
||||||
|
|
||||||
public static final EventId Entity_User_Query = new EventId(25000, "Entity_User_Query");
|
|
||||||
public static final EventId Entity_User_Lookup = new EventId(25001, "Entity_User_Lookup");
|
|
||||||
public static final EventId Entity_User_Persist = new EventId(25002, "Entity_User_Persist");
|
|
||||||
public static final EventId Entity_User_Delete = new EventId(25003, "Entity_User_Delete");
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,40 +0,0 @@
|
||||||
package gr.cite.annotation.authorization;
|
|
||||||
|
|
||||||
import gr.cite.commons.web.authz.policy.AuthorizationRequirement;
|
|
||||||
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
public class AffiliatedAuthorizationRequirement implements AuthorizationRequirement {
|
|
||||||
private final Set<String> requiredPermissions;
|
|
||||||
private final boolean matchAll;
|
|
||||||
|
|
||||||
public AffiliatedAuthorizationRequirement(Set<String> requiredPermissions) {
|
|
||||||
this(false, requiredPermissions);
|
|
||||||
}
|
|
||||||
|
|
||||||
public AffiliatedAuthorizationRequirement(String... requiredPermissions) {
|
|
||||||
this(false, requiredPermissions);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public AffiliatedAuthorizationRequirement(boolean matchAll, Set<String> requiredPermissions) {
|
|
||||||
this.matchAll = matchAll;
|
|
||||||
this.requiredPermissions = requiredPermissions;
|
|
||||||
}
|
|
||||||
|
|
||||||
public AffiliatedAuthorizationRequirement(boolean matchAll, String... requiredPermissions) {
|
|
||||||
this.requiredPermissions = new HashSet<>();
|
|
||||||
this.matchAll = matchAll;
|
|
||||||
this.requiredPermissions.addAll(Arrays.stream(requiredPermissions).distinct().toList());
|
|
||||||
}
|
|
||||||
|
|
||||||
public Set<String> getRequiredPermissions() {
|
|
||||||
return requiredPermissions;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean getMatchAll() {
|
|
||||||
return matchAll;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,22 +0,0 @@
|
||||||
package gr.cite.annotation.authorization;
|
|
||||||
|
|
||||||
import gr.cite.commons.web.authz.policy.AuthorizationResource;
|
|
||||||
|
|
||||||
public class AffiliatedResource extends AuthorizationResource {
|
|
||||||
private Boolean isAffiliated;
|
|
||||||
|
|
||||||
public AffiliatedResource() {
|
|
||||||
}
|
|
||||||
|
|
||||||
public AffiliatedResource(Boolean isAffiliated) {
|
|
||||||
this.isAffiliated = isAffiliated;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Boolean getAffiliated() {
|
|
||||||
return isAffiliated;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setAffiliated(Boolean affiliated) {
|
|
||||||
isAffiliated = affiliated;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,8 +0,0 @@
|
||||||
package gr.cite.annotation.authorization;
|
|
||||||
|
|
||||||
import java.util.EnumSet;
|
|
||||||
|
|
||||||
public enum AuthorizationFlags {
|
|
||||||
None, Permission, Associated, Owner;
|
|
||||||
public static final EnumSet<AuthorizationFlags> OwnerOrPermissionAssociated = EnumSet.of(Owner, Permission, Associated);
|
|
||||||
}
|
|
|
@ -1,9 +0,0 @@
|
||||||
package gr.cite.annotation.authorization;
|
|
||||||
|
|
||||||
public class ClaimNames {
|
|
||||||
public static final String ExternalProviderName = "ExternalProviderName";
|
|
||||||
public static final String TenantCodesClaimName = "TenantCodes";
|
|
||||||
public static final String TenantClaimName = "x-tenant";
|
|
||||||
public static final String GlobalRolesClaimName = "GlobalRoles";
|
|
||||||
public static final String TenantRolesClaimName = "TenantRoles";
|
|
||||||
}
|
|
|
@ -1,6 +0,0 @@
|
||||||
package gr.cite.annotation.authorization;
|
|
||||||
|
|
||||||
import gr.cite.commons.web.authz.policy.AuthorizationRequirement;
|
|
||||||
|
|
||||||
public class OwnedAuthorizationRequirement implements AuthorizationRequirement {
|
|
||||||
}
|
|
|
@ -1,26 +0,0 @@
|
||||||
package gr.cite.annotation.authorization;
|
|
||||||
|
|
||||||
import gr.cite.commons.web.authz.policy.AuthorizationResource;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
public class OwnedResource extends AuthorizationResource {
|
|
||||||
private List<UUID> userIds;
|
|
||||||
|
|
||||||
public OwnedResource(UUID userId) {
|
|
||||||
this(List.of(userId));
|
|
||||||
}
|
|
||||||
|
|
||||||
public OwnedResource(List<UUID> userIds) {
|
|
||||||
this.userIds = userIds;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<UUID> getUserIds() {
|
|
||||||
return userIds;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setUserIds(List<UUID> userIds) {
|
|
||||||
this.userIds = userIds;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,27 +0,0 @@
|
||||||
package gr.cite.annotation.authorization;
|
|
||||||
|
|
||||||
public final class Permission {
|
|
||||||
public static String DeferredAffiliation = "DeferredAffiliation";
|
|
||||||
//User
|
|
||||||
public static String BrowseUser = "BrowseUser";
|
|
||||||
public static String EditUser = "EditUser";
|
|
||||||
public static String DeleteUser = "DeleteUser";
|
|
||||||
|
|
||||||
|
|
||||||
//Tenant
|
|
||||||
public static String BrowseTenant = "BrowseTenant";
|
|
||||||
public static String EditTenant = "EditTenant";
|
|
||||||
public static String DeleteTenant = "DeleteTenant";
|
|
||||||
public static String AllowNoTenant = "AllowNoTenant";
|
|
||||||
|
|
||||||
//Annotation
|
|
||||||
public static final String BrowseAnnotation = "BrowseAnnotation";
|
|
||||||
public static String NewAnnotation = "NewAnnotation";
|
|
||||||
public static String EditAnnotation = "EditAnnotation";
|
|
||||||
public static String DeleteAnnotation = "DeleteAnnotation";
|
|
||||||
|
|
||||||
public static final String BrowseTenantConfiguration = "BrowseTenantConfiguration";
|
|
||||||
public static final String EditTenantConfiguration = "EditTenantConfiguration";
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,39 +0,0 @@
|
||||||
package gr.cite.annotation.authorization;
|
|
||||||
|
|
||||||
import gr.cite.annotation.convention.ConventionService;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
|
|
||||||
import org.springframework.context.annotation.Scope;
|
|
||||||
import org.springframework.stereotype.Service;
|
|
||||||
|
|
||||||
import java.lang.reflect.Field;
|
|
||||||
import java.lang.reflect.Modifier;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
@Service
|
|
||||||
@Scope(value = ConfigurableBeanFactory.SCOPE_SINGLETON)
|
|
||||||
public class PermissionNameProvider {
|
|
||||||
private static final Logger logger = LoggerFactory.getLogger(PermissionNameProvider.class);
|
|
||||||
private final List<String> permissions;
|
|
||||||
|
|
||||||
public PermissionNameProvider(ConventionService conventionService) {
|
|
||||||
this.permissions = new ArrayList<>();
|
|
||||||
Class<Permission> clazz = Permission.class;
|
|
||||||
for (Field f : clazz.getDeclaredFields()) {
|
|
||||||
if (Modifier.isStatic(f.getModifiers())) {
|
|
||||||
try {
|
|
||||||
Object value = f.get(null);
|
|
||||||
if (value != null && !conventionService.isNullOrEmpty((String)value)) this.permissions.add((String)value);
|
|
||||||
} catch (Exception e) {
|
|
||||||
logger.error("Can not load permission " + f.getName() + " " + e.getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<String> getPermissions() {
|
|
||||||
return permissions;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,10 +0,0 @@
|
||||||
package gr.cite.annotation.authorization.authorizationcontentresolver;
|
|
||||||
|
|
||||||
import gr.cite.tools.cache.CacheOptions;
|
|
||||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
|
||||||
import org.springframework.context.annotation.Configuration;
|
|
||||||
|
|
||||||
@Configuration
|
|
||||||
@ConfigurationProperties(prefix = "cache.affiliation")
|
|
||||||
public class AffiliationCacheOptions extends CacheOptions {
|
|
||||||
}
|
|
|
@ -1,95 +0,0 @@
|
||||||
package gr.cite.annotation.authorization.authorizationcontentresolver;
|
|
||||||
|
|
||||||
import gr.cite.annotation.authorization.AffiliatedResource;
|
|
||||||
import gr.cite.annotation.convention.ConventionService;
|
|
||||||
import gr.cite.tools.cache.CacheService;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.stereotype.Service;
|
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Locale;
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
@Service
|
|
||||||
public class AffiliationCacheService extends CacheService<AffiliationCacheService.AffiliationCacheValue> {
|
|
||||||
|
|
||||||
public static class AffiliationCacheValue {
|
|
||||||
|
|
||||||
public AffiliationCacheValue() {
|
|
||||||
}
|
|
||||||
|
|
||||||
public AffiliationCacheValue(UUID userId, UUID entityId, String entityType, AffiliatedResource affiliatedResource) {
|
|
||||||
this.userId = userId;
|
|
||||||
this.entityId = entityId;
|
|
||||||
this.entityType = entityType;
|
|
||||||
this.affiliatedResource = affiliatedResource;
|
|
||||||
}
|
|
||||||
|
|
||||||
private UUID userId;
|
|
||||||
private UUID entityId;
|
|
||||||
private String entityType;
|
|
||||||
private AffiliatedResource affiliatedResource;
|
|
||||||
|
|
||||||
public UUID getUserId() {
|
|
||||||
return userId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setUserId(UUID userId) {
|
|
||||||
this.userId = userId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public UUID getEntityId() {
|
|
||||||
return entityId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setEntityId(UUID entityId) {
|
|
||||||
this.entityId = entityId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getEntityType() {
|
|
||||||
return entityType;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setEntityType(String entityType) {
|
|
||||||
this.entityType = entityType;
|
|
||||||
}
|
|
||||||
|
|
||||||
public AffiliatedResource getAffiliatedResource() {
|
|
||||||
return affiliatedResource;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setAffiliatedResource(AffiliatedResource affiliatedResource) {
|
|
||||||
this.affiliatedResource = affiliatedResource;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private final ConventionService conventionService;
|
|
||||||
@Autowired
|
|
||||||
public AffiliationCacheService(AffiliationCacheOptions options, ConventionService conventionService) {
|
|
||||||
super(options);
|
|
||||||
this.conventionService = conventionService;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Class<AffiliationCacheValue> valueClass() {
|
|
||||||
return AffiliationCacheValue.class;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String keyOf(AffiliationCacheValue value) {
|
|
||||||
return this.buildKey(value.getUserId(), value.getEntityId(), value.getEntityType());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public String buildKey(UUID userId, UUID entityId, String entityType) {
|
|
||||||
if (userId == null) throw new IllegalArgumentException("userId id is required");
|
|
||||||
if (entityId == null) throw new IllegalArgumentException("entityId id is required");
|
|
||||||
if (this.conventionService.isNullOrEmpty(entityType)) throw new IllegalArgumentException("entityType id is required");
|
|
||||||
|
|
||||||
HashMap<String, String> keyParts = new HashMap<>();
|
|
||||||
keyParts.put("$user$", userId.toString().replace("-", "").toLowerCase(Locale.ROOT));
|
|
||||||
keyParts.put("$entity$", entityId.toString().replace("-", "").toLowerCase(Locale.ROOT));
|
|
||||||
keyParts.put("$type$", entityType);
|
|
||||||
return this.generateKey(keyParts);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,20 +0,0 @@
|
||||||
package gr.cite.annotation.authorization.authorizationcontentresolver;
|
|
||||||
|
|
||||||
|
|
||||||
import gr.cite.annotation.authorization.AffiliatedResource;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
public interface AuthorizationContentResolver {
|
|
||||||
AffiliatedResource entityAffiliation(UUID id);
|
|
||||||
|
|
||||||
Map<UUID, AffiliatedResource> entitiesAffiliation(List<UUID> ids);
|
|
||||||
|
|
||||||
List<String> getPermissionNames();
|
|
||||||
|
|
||||||
AffiliatedResource annotationAffiliation(UUID id);
|
|
||||||
|
|
||||||
Map<UUID, AffiliatedResource> annotationsAffiliation(List<UUID> ids);
|
|
||||||
}
|
|
|
@ -1,118 +0,0 @@
|
||||||
package gr.cite.annotation.authorization.authorizationcontentresolver;
|
|
||||||
|
|
||||||
import gr.cite.annotation.authorization.AffiliatedResource;
|
|
||||||
import gr.cite.annotation.authorization.PermissionNameProvider;
|
|
||||||
import gr.cite.annotation.common.enums.IsActive;
|
|
||||||
import gr.cite.annotation.common.scope.user.UserScope;
|
|
||||||
import gr.cite.annotation.data.AnnotationEntity;
|
|
||||||
import gr.cite.annotation.data.EntityUserEntity;
|
|
||||||
import gr.cite.annotation.model.Annotation;
|
|
||||||
import gr.cite.annotation.model.EntityUser;
|
|
||||||
import gr.cite.annotation.query.AnnotationQuery;
|
|
||||||
import gr.cite.annotation.query.EntityUserQuery;
|
|
||||||
import gr.cite.tools.data.query.QueryFactory;
|
|
||||||
import gr.cite.tools.fieldset.BaseFieldSet;
|
|
||||||
import org.springframework.stereotype.Service;
|
|
||||||
import org.springframework.web.context.annotation.RequestScope;
|
|
||||||
|
|
||||||
import java.util.*;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
@Service
|
|
||||||
@RequestScope
|
|
||||||
public class AuthorizationContentResolverImpl implements AuthorizationContentResolver {
|
|
||||||
private final QueryFactory queryFactory;
|
|
||||||
private final UserScope userScope;
|
|
||||||
private final AffiliationCacheService affiliationCacheService;
|
|
||||||
private final PermissionNameProvider permissionNameProvider;
|
|
||||||
public AuthorizationContentResolverImpl(QueryFactory queryFactory, UserScope userScope, AffiliationCacheService affiliationCacheService, PermissionNameProvider permissionNameProvider) {
|
|
||||||
this.queryFactory = queryFactory;
|
|
||||||
this.userScope = userScope;
|
|
||||||
this.affiliationCacheService = affiliationCacheService;
|
|
||||||
this.permissionNameProvider = permissionNameProvider;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public AffiliatedResource entityAffiliation(UUID id) {
|
|
||||||
return this.entitiesAffiliation(List.of(id)).getOrDefault(id, new AffiliatedResource());
|
|
||||||
}
|
|
||||||
@Override
|
|
||||||
public Map<UUID, AffiliatedResource> entitiesAffiliation(List<UUID> ids){
|
|
||||||
UUID userId = this.userScope.getUserIdSafe();
|
|
||||||
Map<UUID, AffiliatedResource> affiliatedResources = new HashMap<>();
|
|
||||||
for (UUID id : ids){
|
|
||||||
affiliatedResources.put(id, new AffiliatedResource());
|
|
||||||
}
|
|
||||||
if (userId == null || !userScope.isSet()) return affiliatedResources;
|
|
||||||
|
|
||||||
List<UUID> idsToResolve = this.getAffiliatedFromCache(ids, userId, affiliatedResources, AnnotationEntity._entityId);
|
|
||||||
if (idsToResolve.isEmpty()) return affiliatedResources;
|
|
||||||
|
|
||||||
List<EntityUserEntity> entityUsers = this.queryFactory.query(EntityUserQuery.class).disableTracking().entityIds(ids).userIds(userId).isActive(IsActive.Active).collectAs(new BaseFieldSet().ensure(EntityUser._id).ensure(EntityUser._entityId));
|
|
||||||
|
|
||||||
for (UUID entityId : entityUsers.stream().map(EntityUserEntity::getEntityId).distinct().toList()){
|
|
||||||
affiliatedResources.get(entityId).setAffiliated(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.ensureAffiliatedInCache(idsToResolve, userId, affiliatedResources, AnnotationEntity._entityId);
|
|
||||||
return affiliatedResources;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<String> getPermissionNames() {
|
|
||||||
return permissionNameProvider.getPermissions();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public AffiliatedResource annotationAffiliation(UUID id) {
|
|
||||||
return this.annotationsAffiliation(List.of(id)).getOrDefault(id, new AffiliatedResource());
|
|
||||||
}
|
|
||||||
@Override
|
|
||||||
public Map<UUID, AffiliatedResource> annotationsAffiliation(List<UUID> ids){
|
|
||||||
UUID userId = this.userScope.getUserIdSafe();
|
|
||||||
Map<UUID, AffiliatedResource> affiliatedResources = new HashMap<>();
|
|
||||||
for (UUID id : ids){
|
|
||||||
affiliatedResources.put(id, new AffiliatedResource());
|
|
||||||
}
|
|
||||||
if (userId == null || !userScope.isSet()) return affiliatedResources;
|
|
||||||
|
|
||||||
List<UUID> idsToResolve = this.getAffiliatedFromCache(ids, userId, affiliatedResources, AnnotationEntity.class.getSimpleName());
|
|
||||||
if (idsToResolve.isEmpty()) return affiliatedResources;
|
|
||||||
|
|
||||||
List<AnnotationEntity> annotationEntities = this.queryFactory.query(AnnotationQuery.class).disableTracking().ids(ids).collectAs(new BaseFieldSet().ensure(Annotation._id).ensure(Annotation._entityId).ensure(Annotation._id));
|
|
||||||
List<EntityUserEntity> entityUsers = this.queryFactory.query(EntityUserQuery.class).disableTracking().entityIds(annotationEntities.stream().map(AnnotationEntity::getEntityId).distinct().toList()).userIds(userId).isActive(IsActive.Active).collectAs(new BaseFieldSet().ensure(EntityUser._id).ensure(EntityUser._entityId));
|
|
||||||
Map<UUID, List<EntityUserEntity>> entityUsersMap = entityUsers.stream().collect(Collectors.groupingBy(EntityUserEntity::getEntityId));
|
|
||||||
|
|
||||||
for (AnnotationEntity annotation : annotationEntities){
|
|
||||||
List<EntityUserEntity> annotationEntityUsers = entityUsersMap.getOrDefault(annotation.getEntityId(), new ArrayList<>());
|
|
||||||
if (!annotationEntityUsers.isEmpty()) {
|
|
||||||
affiliatedResources.get(annotation.getId()).setAffiliated(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.ensureAffiliatedInCache(idsToResolve, userId, affiliatedResources, AnnotationEntity.class.getSimpleName());
|
|
||||||
return affiliatedResources;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private List<UUID> getAffiliatedFromCache(List<UUID> ids, UUID userId, Map<UUID, AffiliatedResource> affiliatedResources, String entityType){
|
|
||||||
List<UUID> idsToResolve = new ArrayList<>();
|
|
||||||
for (UUID id : ids){
|
|
||||||
AffiliationCacheService.AffiliationCacheValue cacheValue = this.affiliationCacheService.lookup(this.affiliationCacheService.buildKey(userId, id, entityType));
|
|
||||||
if (cacheValue != null) affiliatedResources.put(id, cacheValue.getAffiliatedResource());
|
|
||||||
else idsToResolve.add(id);
|
|
||||||
}
|
|
||||||
return idsToResolve;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ensureAffiliatedInCache(List<UUID> idsToResolve, UUID userId, Map<UUID, AffiliatedResource> affiliatedResources, String entityType){
|
|
||||||
for (UUID id : idsToResolve){
|
|
||||||
AffiliatedResource affiliatedResource = affiliatedResources.getOrDefault(id, null);
|
|
||||||
if (affiliatedResource != null) {
|
|
||||||
AffiliationCacheService.AffiliationCacheValue cacheValue = new AffiliationCacheService.AffiliationCacheValue(userId, id, entityType, affiliatedResource);
|
|
||||||
this.affiliationCacheService.put(cacheValue);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,58 +0,0 @@
|
||||||
package gr.cite.annotation.common;
|
|
||||||
|
|
||||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
|
||||||
import com.fasterxml.jackson.databind.ObjectReader;
|
|
||||||
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
|
|
||||||
import gr.cite.tools.logging.LoggerService;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
|
|
||||||
import org.springframework.context.annotation.Scope;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
@Component
|
|
||||||
@Scope(ConfigurableBeanFactory.SCOPE_SINGLETON)
|
|
||||||
public class JsonHandlingService {
|
|
||||||
private final ObjectMapper objectMapper;
|
|
||||||
|
|
||||||
public JsonHandlingService() {
|
|
||||||
this.objectMapper = new ObjectMapper();
|
|
||||||
this.objectMapper.registerModule(new JavaTimeModule());
|
|
||||||
}
|
|
||||||
|
|
||||||
public String toJson(Object item) throws JsonProcessingException {
|
|
||||||
if (item == null) return null;
|
|
||||||
return this.objectMapper.writeValueAsString(item);
|
|
||||||
}
|
|
||||||
|
|
||||||
public String toJsonSafe(Object item) {
|
|
||||||
if (item == null) return null;
|
|
||||||
try {
|
|
||||||
return this.objectMapper.writeValueAsString(item);
|
|
||||||
} catch (Exception ex) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public <T> T fromJson(Class<T> type, String json) throws JsonProcessingException {
|
|
||||||
if (json == null) return null;
|
|
||||||
return this.objectMapper.readValue(json, type);
|
|
||||||
}
|
|
||||||
|
|
||||||
public HashMap<String, String> mapFromJson(String json) throws JsonProcessingException {
|
|
||||||
ObjectReader reader = this.objectMapper.readerFor(Map.class);
|
|
||||||
return reader.readValue(json);
|
|
||||||
}
|
|
||||||
|
|
||||||
public <T> T fromJsonSafe(Class<T> type, String json) {
|
|
||||||
if (json == null) return null;
|
|
||||||
try {
|
|
||||||
return this.objectMapper.readValue(json, type);
|
|
||||||
} catch (Exception ex) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,8 +0,0 @@
|
||||||
package gr.cite.annotation.common;
|
|
||||||
|
|
||||||
public class StringUtils {
|
|
||||||
|
|
||||||
public static Boolean isNullOrEmpty(String string) {
|
|
||||||
return string == null || string.isEmpty();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,117 +0,0 @@
|
||||||
package gr.cite.annotation.common;
|
|
||||||
|
|
||||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
|
||||||
import gr.cite.annotation.common.types.xml.XmlSerializable;
|
|
||||||
import jakarta.xml.bind.JAXBContext;
|
|
||||||
import jakarta.xml.bind.JAXBException;
|
|
||||||
import jakarta.xml.bind.Marshaller;
|
|
||||||
import jakarta.xml.bind.Unmarshaller;
|
|
||||||
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
|
|
||||||
import org.springframework.context.annotation.Scope;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
import org.w3c.dom.Document;
|
|
||||||
import org.xml.sax.InputSource;
|
|
||||||
import org.xml.sax.SAXException;
|
|
||||||
|
|
||||||
import javax.management.InvalidApplicationException;
|
|
||||||
import javax.xml.parsers.DocumentBuilder;
|
|
||||||
import javax.xml.parsers.DocumentBuilderFactory;
|
|
||||||
import javax.xml.parsers.ParserConfigurationException;
|
|
||||||
import javax.xml.transform.OutputKeys;
|
|
||||||
import javax.xml.transform.Transformer;
|
|
||||||
import javax.xml.transform.TransformerException;
|
|
||||||
import javax.xml.transform.TransformerFactory;
|
|
||||||
import javax.xml.transform.dom.DOMSource;
|
|
||||||
import javax.xml.transform.stream.StreamResult;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.StringReader;
|
|
||||||
import java.io.StringWriter;
|
|
||||||
|
|
||||||
@Component
|
|
||||||
@Scope(value = ConfigurableBeanFactory.SCOPE_SINGLETON)
|
|
||||||
public class XmlHandlingService {
|
|
||||||
|
|
||||||
public String generateXml(Document doc) throws TransformerException {
|
|
||||||
TransformerFactory tFact = TransformerFactory.newInstance();
|
|
||||||
Transformer trans = tFact.newTransformer();
|
|
||||||
StringWriter writer = new StringWriter();
|
|
||||||
StreamResult result = new StreamResult(writer);
|
|
||||||
DOMSource source = new DOMSource(doc);
|
|
||||||
trans.setOutputProperty(OutputKeys.INDENT, "yes");
|
|
||||||
trans.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2");
|
|
||||||
trans.transform(source, result);
|
|
||||||
return writer.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
public String toXml(Object item) throws JsonProcessingException, JAXBException, ParserConfigurationException, InvalidApplicationException, TransformerException {
|
|
||||||
if (XmlSerializable.class.isAssignableFrom(item.getClass())){
|
|
||||||
Document document = this.getDocument();
|
|
||||||
if (document == null) throw new InvalidApplicationException("Can not create document");
|
|
||||||
document.appendChild(((XmlSerializable)item).toXml(document));
|
|
||||||
return this.generateXml(document);
|
|
||||||
}
|
|
||||||
|
|
||||||
JAXBContext context = JAXBContext.newInstance(item.getClass());
|
|
||||||
Marshaller marshaller = context.createMarshaller();
|
|
||||||
StringWriter out = new StringWriter();
|
|
||||||
marshaller.marshal(item, out);
|
|
||||||
return out.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
public String toXmlSafe(Object item) {
|
|
||||||
if (item == null) return null;
|
|
||||||
try {
|
|
||||||
return this.toXml(item);
|
|
||||||
} catch (Exception ex) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public <T> T fromXml(Class<T> type, String xmlString) throws JAXBException, InstantiationException, IllegalAccessException, ParserConfigurationException, IOException, SAXException {
|
|
||||||
if (XmlSerializable.class.isAssignableFrom(type)){
|
|
||||||
XmlSerializable<T> object = (XmlSerializable<T>)type.newInstance();
|
|
||||||
return object.fromXml(this.getDocument(xmlString).getDocumentElement());
|
|
||||||
} else {
|
|
||||||
JAXBContext jaxbContext = JAXBContext.newInstance(type);
|
|
||||||
Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
|
|
||||||
|
|
||||||
return (T) jaxbUnmarshaller.unmarshal(new StringReader(xmlString));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public <T> T fromXmlSafe(Class<T> type, String xmlString) {
|
|
||||||
if (xmlString == null) return null;
|
|
||||||
try {
|
|
||||||
return this.fromXml(type, xmlString);
|
|
||||||
} catch (Exception ex) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// public <T extends XmlSerializable<T>> T xmlSerializableFromXml(Class<T> type, String xmlString) throws JAXBException, InstantiationException, IllegalAccessException, ParserConfigurationException, IOException, SAXException {
|
|
||||||
// T object = type.newInstance();
|
|
||||||
// return (T) object.fromXml(this.getDocument(xmlString).getDocumentElement());
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// public <T extends XmlSerializable<T>> T xmlSerializableFromXmlSafe(Class<T> type, String xmlString) {
|
|
||||||
// if (xmlString == null) return null;
|
|
||||||
// try {
|
|
||||||
// return this.xmlSerializableFromXml(type, xmlString);
|
|
||||||
// } catch (Exception ex) {
|
|
||||||
// return null;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
public Document getDocument(String xml) throws ParserConfigurationException, IOException, SAXException {
|
|
||||||
DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
|
|
||||||
DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
|
|
||||||
InputSource inputStream = new InputSource(new StringReader(xml));
|
|
||||||
return docBuilder.parse(inputStream);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Document getDocument() throws ParserConfigurationException {
|
|
||||||
DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
|
|
||||||
DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
|
|
||||||
return docBuilder.newDocument();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,30 +0,0 @@
|
||||||
package gr.cite.annotation.common.enums;
|
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonValue;
|
|
||||||
import gr.cite.annotation.data.conventers.DatabaseEnum;
|
|
||||||
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
public enum AnnotationProtectionType implements DatabaseEnum<Short> {
|
|
||||||
|
|
||||||
Private((short) 0),
|
|
||||||
EntityAccessors((short) 1);
|
|
||||||
|
|
||||||
private final Short value;
|
|
||||||
|
|
||||||
AnnotationProtectionType(Short value) {
|
|
||||||
this.value = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
@JsonValue
|
|
||||||
public Short getValue() {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final Map<Short, AnnotationProtectionType> map = EnumUtils.getEnumValueMap(AnnotationProtectionType.class);
|
|
||||||
|
|
||||||
public static AnnotationProtectionType of(Short i) {
|
|
||||||
return map.get(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,29 +0,0 @@
|
||||||
package gr.cite.annotation.common.enums;
|
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonValue;
|
|
||||||
import gr.cite.annotation.data.conventers.DatabaseEnum;
|
|
||||||
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
public enum ContactInfoType implements DatabaseEnum<Short> {
|
|
||||||
Email((short) 0),
|
|
||||||
MobilePhone((short) 1),
|
|
||||||
LandLinePhone((short) 2);
|
|
||||||
private final Short value;
|
|
||||||
|
|
||||||
ContactInfoType(Short value) {
|
|
||||||
this.value = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@JsonValue
|
|
||||||
public Short getValue() {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final Map<Short, ContactInfoType> map = EnumUtils.getEnumValueMap(ContactInfoType.class);
|
|
||||||
|
|
||||||
public static ContactInfoType of(Short i) {
|
|
||||||
return map.get(i);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,16 +0,0 @@
|
||||||
package gr.cite.annotation.common.enums;
|
|
||||||
|
|
||||||
import gr.cite.annotation.data.conventers.DatabaseEnum;
|
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
public class EnumUtils {
|
|
||||||
public static <EnumType extends Enum<EnumType> & DatabaseEnum<EnumValue>, EnumValue> Map<EnumValue, EnumType> getEnumValueMap(Class<EnumType> enumType){
|
|
||||||
HashMap<EnumValue, EnumType> map = new HashMap<>();
|
|
||||||
for (EnumType v : enumType.getEnumConstants()) {
|
|
||||||
map.put(v.getValue(), v);
|
|
||||||
}
|
|
||||||
return map;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,28 +0,0 @@
|
||||||
package gr.cite.annotation.common.enums;
|
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonValue;
|
|
||||||
import gr.cite.annotation.data.conventers.DatabaseEnum;
|
|
||||||
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
public enum IsActive implements DatabaseEnum<Short> {
|
|
||||||
Inactive((short) 0),
|
|
||||||
Active((short) 1);
|
|
||||||
|
|
||||||
private final Short value;
|
|
||||||
|
|
||||||
IsActive(Short value) {
|
|
||||||
this.value = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
@JsonValue
|
|
||||||
public Short getValue() {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final Map<Short, IsActive> map = EnumUtils.getEnumValueMap(IsActive.class);
|
|
||||||
|
|
||||||
public static IsActive of(Short i) {
|
|
||||||
return map.get(i);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,29 +0,0 @@
|
||||||
package gr.cite.annotation.common.enums;
|
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonValue;
|
|
||||||
import gr.cite.annotation.data.conventers.DatabaseEnum;
|
|
||||||
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
public enum TenantConfigurationType implements DatabaseEnum<Short> {
|
|
||||||
EMAIL_CLIENT_CONFIGURATION((short)1),
|
|
||||||
DEFAULT_USER_LOCALE((short)3),
|
|
||||||
NOTIFIER_LIST((short)4);
|
|
||||||
|
|
||||||
private final Short value;
|
|
||||||
|
|
||||||
TenantConfigurationType(Short value) {
|
|
||||||
this.value = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
@JsonValue
|
|
||||||
public Short getValue() {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final Map<Short, TenantConfigurationType> map = EnumUtils.getEnumValueMap(TenantConfigurationType.class);
|
|
||||||
|
|
||||||
public static TenantConfigurationType of(Short i) {
|
|
||||||
return map.get(i);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,58 +0,0 @@
|
||||||
package gr.cite.annotation.common.lock;
|
|
||||||
|
|
||||||
import org.springframework.stereotype.Service;
|
|
||||||
|
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
|
||||||
import java.util.concurrent.locks.ReentrantLock;
|
|
||||||
|
|
||||||
@Service
|
|
||||||
public class LockByKeyManager {
|
|
||||||
|
|
||||||
private static class LockWrapper {
|
|
||||||
private final ReentrantLock lock = new ReentrantLock();
|
|
||||||
private final AtomicInteger numberOfThreadsInQueue = new AtomicInteger(1);
|
|
||||||
|
|
||||||
private LockWrapper addThreadInQueue() {
|
|
||||||
numberOfThreadsInQueue.incrementAndGet();
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
private int removeThreadFromQueue() {
|
|
||||||
return numberOfThreadsInQueue.decrementAndGet();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final ConcurrentHashMap<String, LockWrapper> locks = new ConcurrentHashMap<String, LockWrapper>();
|
|
||||||
|
|
||||||
public void lock(String key) {
|
|
||||||
LockWrapper lockWrapper = locks.compute(key, (k, v) -> v == null ? new LockWrapper() : v.addThreadInQueue());
|
|
||||||
lockWrapper.lock.lock();
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean tryLock(String key, long timeout, TimeUnit unit) throws InterruptedException {
|
|
||||||
LockWrapper lockWrapper = null;
|
|
||||||
try {
|
|
||||||
lockWrapper = locks.compute(key, (k, v) -> v == null ? new LockWrapper() : v.addThreadInQueue());
|
|
||||||
return lockWrapper.lock.tryLock(timeout, unit);
|
|
||||||
} catch (Exception ex){
|
|
||||||
if (lockWrapper != null && lockWrapper.removeThreadFromQueue() == 0) {
|
|
||||||
// NB : We pass in the specific value to remove to handle the case where another thread would queue right before the removal
|
|
||||||
locks.remove(key, lockWrapper);
|
|
||||||
}
|
|
||||||
throw ex;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void unlock(String key) {
|
|
||||||
LockWrapper lockWrapper = locks.get(key);
|
|
||||||
lockWrapper.lock.unlock();
|
|
||||||
if (lockWrapper.removeThreadFromQueue() == 0) {
|
|
||||||
// NB : We pass in the specific value to remove to handle the case where another thread would queue right before the removal
|
|
||||||
locks.remove(key, lockWrapper);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,125 +0,0 @@
|
||||||
package gr.cite.annotation.common.scope.fake;
|
|
||||||
|
|
||||||
import org.springframework.util.Assert;
|
|
||||||
import org.springframework.web.context.request.RequestAttributes;
|
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.LinkedHashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
public class FakeRequestAttributes implements RequestAttributes {
|
|
||||||
private final Map<String, Object> requestAttributeMap = new HashMap<>();
|
|
||||||
private final Map<String, Runnable> requestDestructionCallbacks = new LinkedHashMap<>(8);
|
|
||||||
private volatile boolean requestActive = true;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Object getAttribute(String name, int scope) {
|
|
||||||
if (scope == RequestAttributes.SCOPE_REQUEST) {
|
|
||||||
if (!isRequestActive()) {
|
|
||||||
throw new IllegalStateException("Cannot ask for request attribute - request is not active anymore!");
|
|
||||||
}
|
|
||||||
return this.requestAttributeMap.get(name);
|
|
||||||
} else {
|
|
||||||
throw new IllegalStateException("Only " + RequestAttributes.SCOPE_REQUEST + " allowed for " + FakeRequestAttributes.class.getSimpleName());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setAttribute(String name, Object value, int scope) {
|
|
||||||
if (scope == RequestAttributes.SCOPE_REQUEST) {
|
|
||||||
if (!isRequestActive()) {
|
|
||||||
throw new IllegalStateException("Cannot set request attribute - request is not active anymore!");
|
|
||||||
}
|
|
||||||
this.requestAttributeMap.put(name, value);
|
|
||||||
} else {
|
|
||||||
throw new IllegalStateException("Only " + RequestAttributes.SCOPE_REQUEST + " allowed for " + FakeRequestAttributes.class.getSimpleName());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void removeAttribute(String name, int scope) {
|
|
||||||
if (scope == RequestAttributes.SCOPE_REQUEST) {
|
|
||||||
if (isRequestActive()) {
|
|
||||||
removeRequestDestructionCallback(name);
|
|
||||||
this.requestAttributeMap.remove(name);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
throw new IllegalStateException("Only " + RequestAttributes.SCOPE_REQUEST + " allowed for " + FakeRequestAttributes.class.getSimpleName());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String[] getAttributeNames(int scope) {
|
|
||||||
if (scope == RequestAttributes.SCOPE_REQUEST) {
|
|
||||||
if (!isRequestActive()) {
|
|
||||||
throw new IllegalStateException("Cannot ask for request attributes - request is not active anymore!");
|
|
||||||
}
|
|
||||||
return this.requestAttributeMap.keySet().toArray(new String[0]);
|
|
||||||
} else {
|
|
||||||
throw new IllegalStateException("Only " + RequestAttributes.SCOPE_REQUEST + " allowed for " + FakeRequestAttributes.class.getSimpleName());
|
|
||||||
}
|
|
||||||
//return new String[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void registerDestructionCallback(String name, Runnable callback, int scope) {
|
|
||||||
if (scope == SCOPE_REQUEST) {
|
|
||||||
registerRequestDestructionCallback(name, callback);
|
|
||||||
} else {
|
|
||||||
throw new IllegalStateException("Only " + RequestAttributes.SCOPE_REQUEST + " allowed for " + FakeRequestAttributes.class.getSimpleName());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected final void registerRequestDestructionCallback(String name, Runnable callback) {
|
|
||||||
Assert.notNull(name, "Name must not be null");
|
|
||||||
Assert.notNull(callback, "Callback must not be null");
|
|
||||||
synchronized (this.requestDestructionCallbacks) {
|
|
||||||
this.requestDestructionCallbacks.put(name, callback);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Object resolveReference(String key) {
|
|
||||||
// Not supported
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getSessionId() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Object getSessionMutex() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void requestCompleted() {
|
|
||||||
executeRequestDestructionCallbacks();
|
|
||||||
for (String name : getAttributeNames(RequestAttributes.SCOPE_REQUEST)) {
|
|
||||||
this.removeAttribute(name, RequestAttributes.SCOPE_REQUEST);
|
|
||||||
}
|
|
||||||
this.requestActive = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private final boolean isRequestActive() {
|
|
||||||
return this.requestActive;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private final void removeRequestDestructionCallback(String name) {
|
|
||||||
Assert.notNull(name, "Name must not be null");
|
|
||||||
synchronized (this.requestDestructionCallbacks) {
|
|
||||||
this.requestDestructionCallbacks.remove(name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void executeRequestDestructionCallbacks() {
|
|
||||||
synchronized (this.requestDestructionCallbacks) {
|
|
||||||
for (Runnable runnable : this.requestDestructionCallbacks.values()) {
|
|
||||||
runnable.run();
|
|
||||||
}
|
|
||||||
this.requestDestructionCallbacks.clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,40 +0,0 @@
|
||||||
package gr.cite.annotation.common.scope.fake;
|
|
||||||
|
|
||||||
import org.springframework.web.context.request.RequestAttributes;
|
|
||||||
import org.springframework.web.context.request.RequestContextHolder;
|
|
||||||
|
|
||||||
import java.io.Closeable;
|
|
||||||
|
|
||||||
public class FakeRequestScope implements Closeable {
|
|
||||||
private RequestAttributes initialRequestAttributes = null;
|
|
||||||
private FakeRequestAttributes currentRequestAttributes = null;
|
|
||||||
boolean isInUse = false;
|
|
||||||
|
|
||||||
public FakeRequestScope() {
|
|
||||||
this.reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void reset() {
|
|
||||||
this.close();
|
|
||||||
this.isInUse = true;
|
|
||||||
|
|
||||||
this.initialRequestAttributes = RequestContextHolder.getRequestAttributes();
|
|
||||||
this.currentRequestAttributes = new FakeRequestAttributes();
|
|
||||||
RequestContextHolder.setRequestAttributes(this.currentRequestAttributes);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void close() {
|
|
||||||
if (!this.isInUse) return;
|
|
||||||
this.isInUse = false;
|
|
||||||
|
|
||||||
if (initialRequestAttributes != null) RequestContextHolder.setRequestAttributes(initialRequestAttributes);
|
|
||||||
else RequestContextHolder.resetRequestAttributes();
|
|
||||||
|
|
||||||
if (currentRequestAttributes != null) currentRequestAttributes.requestCompleted();
|
|
||||||
|
|
||||||
this.initialRequestAttributes = null;
|
|
||||||
this.currentRequestAttributes = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,9 +0,0 @@
|
||||||
package gr.cite.annotation.common.scope.tenant;
|
|
||||||
|
|
||||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
|
||||||
import org.springframework.context.annotation.Configuration;
|
|
||||||
|
|
||||||
@Configuration
|
|
||||||
@EnableConfigurationProperties(MultitenancyProperties.class)
|
|
||||||
public class MultitenancyConfiguration {
|
|
||||||
}
|
|
|
@ -1,29 +0,0 @@
|
||||||
package gr.cite.annotation.common.scope.tenant;
|
|
||||||
|
|
||||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
|
||||||
|
|
||||||
@ConfigurationProperties(prefix = "tenant.multitenancy")
|
|
||||||
public class MultitenancyProperties {
|
|
||||||
private boolean isMultitenant;
|
|
||||||
private String defaultTenantCode;
|
|
||||||
|
|
||||||
public boolean isMultitenant() {
|
|
||||||
return isMultitenant;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setIsMultitenant(boolean multitenant) {
|
|
||||||
isMultitenant = multitenant;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setMultitenant(boolean multitenant) {
|
|
||||||
isMultitenant = multitenant;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getDefaultTenantCode() {
|
|
||||||
return defaultTenantCode;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setDefaultTenantCode(String defaultTenantCode) {
|
|
||||||
this.defaultTenantCode = defaultTenantCode;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,88 +0,0 @@
|
||||||
package gr.cite.annotation.common.scope.tenant;
|
|
||||||
|
|
||||||
import gr.cite.annotation.data.TenantEntityManager;
|
|
||||||
import gr.cite.annotation.data.tenant.TenantScopedBaseEntity;
|
|
||||||
import jakarta.persistence.EntityManager;
|
|
||||||
import org.hibernate.Session;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
import org.springframework.web.context.annotation.RequestScope;
|
|
||||||
|
|
||||||
import javax.management.InvalidApplicationException;
|
|
||||||
import java.util.UUID;
|
|
||||||
import java.util.concurrent.atomic.AtomicReference;
|
|
||||||
|
|
||||||
@Component
|
|
||||||
@RequestScope
|
|
||||||
public class TenantScope {
|
|
||||||
public static final String TenantReplaceParameter = "::TenantCode::";
|
|
||||||
private final MultitenancyProperties multitenancy;
|
|
||||||
private final AtomicReference<UUID> tenant = new AtomicReference<>();
|
|
||||||
private final AtomicReference<String> tenantCode = new AtomicReference<>();
|
|
||||||
private final AtomicReference<UUID> initialTenant = new AtomicReference<>();
|
|
||||||
private final AtomicReference<String> initialTenantCode = new AtomicReference<>();
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
public TenantScope(MultitenancyProperties multitenancy) {
|
|
||||||
this.multitenancy = multitenancy;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Boolean isMultitenant() {
|
|
||||||
return this.multitenancy.isMultitenant();
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getDefaultTenantCode() {
|
|
||||||
return this.multitenancy.getDefaultTenantCode();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Boolean isSet() {
|
|
||||||
if (!this.isMultitenant())
|
|
||||||
return Boolean.TRUE;
|
|
||||||
return this.tenant.get() != null || this.isDefaultTenant();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Boolean isDefaultTenant() {
|
|
||||||
if (!this.isMultitenant())
|
|
||||||
return Boolean.TRUE;
|
|
||||||
return this.multitenancy.getDefaultTenantCode().equalsIgnoreCase(this.tenantCode.get());
|
|
||||||
}
|
|
||||||
|
|
||||||
public UUID getTenant() throws InvalidApplicationException {
|
|
||||||
if (!this.isMultitenant())
|
|
||||||
return null;
|
|
||||||
if (this.tenant.get() == null && !this.isDefaultTenant())
|
|
||||||
throw new InvalidApplicationException("tenant not set");
|
|
||||||
return this.isDefaultTenant() ? null : this.tenant.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getTenantCode() throws InvalidApplicationException {
|
|
||||||
if (!this.isMultitenant())
|
|
||||||
return null;
|
|
||||||
if (this.tenantCode.get() == null)
|
|
||||||
throw new InvalidApplicationException("tenant not set");
|
|
||||||
return this.tenantCode.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setTempTenant(TenantEntityManager entityManager, UUID tenant, String tenantCode) throws InvalidApplicationException {
|
|
||||||
this.tenant.set(tenant);
|
|
||||||
this.tenantCode.set(tenantCode);
|
|
||||||
|
|
||||||
entityManager.reloadTenantFilters();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void removeTempTenant(TenantEntityManager entityManager) throws InvalidApplicationException {
|
|
||||||
this.tenant.set(this.initialTenant.get());
|
|
||||||
this.tenantCode.set(this.initialTenantCode.get());
|
|
||||||
|
|
||||||
entityManager.reloadTenantFilters();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setTenant(UUID tenant, String tenantCode) {
|
|
||||||
if (this.isMultitenant()) {
|
|
||||||
this.tenant.set(tenant);
|
|
||||||
this.initialTenant.set(tenant);
|
|
||||||
this.tenantCode.set(tenantCode);
|
|
||||||
this.initialTenantCode.set(tenantCode);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,8 +0,0 @@
|
||||||
package gr.cite.annotation.common.scope.tenant;
|
|
||||||
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
public interface TenantScoped {
|
|
||||||
void setTenantId(UUID tenantId);
|
|
||||||
UUID getTenantId();
|
|
||||||
}
|
|
|
@ -1,34 +0,0 @@
|
||||||
package gr.cite.annotation.common.scope.user;
|
|
||||||
|
|
||||||
import gr.cite.tools.logging.LoggerService;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
import org.springframework.web.context.annotation.RequestScope;
|
|
||||||
|
|
||||||
import javax.management.InvalidApplicationException;
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
@Component
|
|
||||||
@RequestScope
|
|
||||||
public class UserScope {
|
|
||||||
private static final LoggerService logger = new LoggerService(LoggerFactory.getLogger(UserScope.class));
|
|
||||||
private UUID userId = null;
|
|
||||||
|
|
||||||
public Boolean isSet(){
|
|
||||||
return this.userId != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public UUID getUserId() throws InvalidApplicationException {
|
|
||||||
if (this.userId == null) throw new InvalidApplicationException("user not set");
|
|
||||||
return this.userId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public UUID getUserIdSafe() {
|
|
||||||
return this.userId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setUserId(UUID userId) {
|
|
||||||
this.userId = userId;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,60 +0,0 @@
|
||||||
package gr.cite.annotation.common.types.user;
|
|
||||||
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
public class AdditionalInfoEntity {
|
|
||||||
private String avatarUrl;
|
|
||||||
private String timezone;
|
|
||||||
private String culture;
|
|
||||||
private String language;
|
|
||||||
private String roleOrganization;
|
|
||||||
private UUID organizationId;
|
|
||||||
|
|
||||||
public String getAvatarUrl() {
|
|
||||||
return avatarUrl;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setAvatarUrl(String avatarUrl) {
|
|
||||||
this.avatarUrl = avatarUrl;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getTimezone() {
|
|
||||||
return timezone;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setTimezone(String timezone) {
|
|
||||||
this.timezone = timezone;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getCulture() {
|
|
||||||
return culture;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setCulture(String culture) {
|
|
||||||
this.culture = culture;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getLanguage() {
|
|
||||||
return language;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setLanguage(String language) {
|
|
||||||
this.language = language;
|
|
||||||
}
|
|
||||||
|
|
||||||
public UUID getOrganizationId() {
|
|
||||||
return organizationId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setOrganizationId(UUID organizationId) {
|
|
||||||
this.organizationId = organizationId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getRoleOrganization() {
|
|
||||||
return roleOrganization;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setRoleOrganization(String roleOrganization) {
|
|
||||||
this.roleOrganization = roleOrganization;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,87 +0,0 @@
|
||||||
package gr.cite.annotation.common.types.xml;
|
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
import org.w3c.dom.Document;
|
|
||||||
import org.w3c.dom.Element;
|
|
||||||
import org.w3c.dom.Node;
|
|
||||||
import org.w3c.dom.NodeList;
|
|
||||||
import org.xml.sax.InputSource;
|
|
||||||
import org.xml.sax.SAXException;
|
|
||||||
|
|
||||||
import javax.xml.parsers.DocumentBuilder;
|
|
||||||
import javax.xml.parsers.DocumentBuilderFactory;
|
|
||||||
import javax.xml.parsers.ParserConfigurationException;
|
|
||||||
import javax.xml.transform.OutputKeys;
|
|
||||||
import javax.xml.transform.Transformer;
|
|
||||||
import javax.xml.transform.TransformerException;
|
|
||||||
import javax.xml.transform.TransformerFactory;
|
|
||||||
import javax.xml.transform.dom.DOMSource;
|
|
||||||
import javax.xml.transform.stream.StreamResult;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.StringReader;
|
|
||||||
import java.io.StringWriter;
|
|
||||||
|
|
||||||
|
|
||||||
public class XmlBuilder {
|
|
||||||
private static final Logger logger = LoggerFactory.getLogger(XmlBuilder.class);
|
|
||||||
|
|
||||||
public static Document getDocument() {
|
|
||||||
DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
|
|
||||||
DocumentBuilder docBuilder;
|
|
||||||
try {
|
|
||||||
docBuilder = docFactory.newDocumentBuilder();
|
|
||||||
Document doc = docBuilder.newDocument();
|
|
||||||
return doc;
|
|
||||||
} catch (ParserConfigurationException e) {
|
|
||||||
// TODO Auto-generated catch block
|
|
||||||
logger.error(e.getMessage(), e);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String generateXml(Document doc) {
|
|
||||||
TransformerFactory tFact = TransformerFactory.newInstance();
|
|
||||||
Transformer trans;
|
|
||||||
try {
|
|
||||||
trans = tFact.newTransformer();
|
|
||||||
StringWriter writer = new StringWriter();
|
|
||||||
StreamResult result = new StreamResult(writer);
|
|
||||||
DOMSource source = new DOMSource(doc);
|
|
||||||
trans.setOutputProperty(OutputKeys.INDENT, "yes");
|
|
||||||
trans.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2");
|
|
||||||
trans.transform(source, result);
|
|
||||||
return writer.toString();
|
|
||||||
} catch (TransformerException e) {
|
|
||||||
// TODO Auto-generated catch block
|
|
||||||
logger.error(e.getMessage(), e);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Document fromXml(String xml) {
|
|
||||||
DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
|
|
||||||
DocumentBuilder docBuilder;
|
|
||||||
try {
|
|
||||||
docBuilder = docFactory.newDocumentBuilder();
|
|
||||||
InputSource inputStream = new InputSource(new StringReader(xml));
|
|
||||||
Document doc = docBuilder.parse(inputStream);
|
|
||||||
return doc;
|
|
||||||
} catch (ParserConfigurationException | SAXException | IOException e) {
|
|
||||||
// TODO Auto-generated catch block
|
|
||||||
logger.error(e.getMessage(), e);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public static Element getNodeFromListByTagName(NodeList list, String tagName) {
|
|
||||||
for (int temp = 0; temp < list.getLength(); temp++) {
|
|
||||||
Node element = list.item(temp);
|
|
||||||
if (element.getNodeType() == Node.ELEMENT_NODE) {
|
|
||||||
if (element.getNodeName().equals(tagName)) return (Element) element;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,11 +0,0 @@
|
||||||
package gr.cite.annotation.common.types.xml;
|
|
||||||
|
|
||||||
|
|
||||||
import org.w3c.dom.Document;
|
|
||||||
import org.w3c.dom.Element;
|
|
||||||
|
|
||||||
public interface XmlSerializable<T> {
|
|
||||||
Element toXml(Document doc);
|
|
||||||
|
|
||||||
T fromXml(Element item);
|
|
||||||
}
|
|
|
@ -1,63 +0,0 @@
|
||||||
package gr.cite.annotation.common.validation;
|
|
||||||
|
|
||||||
import gr.cite.annotation.convention.ConventionService;
|
|
||||||
import gr.cite.annotation.errorcode.ErrorThesaurusProperties;
|
|
||||||
import gr.cite.tools.exception.MyValidationException;
|
|
||||||
import gr.cite.tools.validation.AbstractValidator;
|
|
||||||
import gr.cite.tools.validation.ValidationResult;
|
|
||||||
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
public abstract class BaseValidator<T> extends AbstractValidator<T> {
|
|
||||||
protected final ConventionService conventionService;
|
|
||||||
protected final ErrorThesaurusProperties errors;
|
|
||||||
|
|
||||||
protected BaseValidator(ConventionService conventionService, ErrorThesaurusProperties errors) {
|
|
||||||
this.conventionService = conventionService;
|
|
||||||
this.errors = errors;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void validateForce(Object target) {
|
|
||||||
this.validate(target);
|
|
||||||
ValidationResult result = result();
|
|
||||||
if (!result.isValid()) {
|
|
||||||
List<Map.Entry<String, List<String>>> errorsMap = this.flattenValidationResult();
|
|
||||||
throw new MyValidationException(this.errors.getModelValidation().getCode(), errorsMap);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected Boolean isValidGuid(UUID guid) {
|
|
||||||
return this.conventionService.isValidGuid(guid);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected Boolean isValidHash(String hash) {
|
|
||||||
return this.conventionService.isValidHash(hash);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected Boolean isEmpty(String value) {
|
|
||||||
return this.conventionService.isNullOrEmpty(value);
|
|
||||||
}
|
|
||||||
protected Boolean isListNullOrEmpty(List<?> value) {
|
|
||||||
return this.conventionService.isListNullOrEmpty(value);
|
|
||||||
}
|
|
||||||
protected Boolean isNull(Object value) {
|
|
||||||
return value == null;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected Boolean isNull(Collection<?> value) {
|
|
||||||
return value == null;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected Boolean lessEqualLength(String value, int size) {
|
|
||||||
return value.length() <= size;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected Boolean lessEqual(Integer value, int target) {
|
|
||||||
return value <= target;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,43 +0,0 @@
|
||||||
package gr.cite.annotation.common.validation;
|
|
||||||
|
|
||||||
import gr.cite.annotation.convention.ConventionService;
|
|
||||||
import gr.cite.annotation.errorcode.ErrorThesaurusProperties;
|
|
||||||
import gr.cite.tools.validation.specification.Specification;
|
|
||||||
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
|
|
||||||
import org.springframework.context.MessageSource;
|
|
||||||
import org.springframework.context.annotation.Scope;
|
|
||||||
import org.springframework.context.i18n.LocaleContextHolder;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
@Component(UuidValidator.ValidatorName)
|
|
||||||
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
|
|
||||||
public class UuidValidator extends BaseValidator<UUID> {
|
|
||||||
|
|
||||||
public static final String ValidatorName = "UuidValidator";
|
|
||||||
|
|
||||||
private final MessageSource messageSource;
|
|
||||||
|
|
||||||
protected UuidValidator(ConventionService conventionService, ErrorThesaurusProperties errors, MessageSource messageSource) {
|
|
||||||
super(conventionService, errors);
|
|
||||||
this.messageSource = messageSource;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Class<UUID> modelClass() {
|
|
||||||
return UUID.class;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected List<Specification> specifications(UUID item) {
|
|
||||||
return Collections.singletonList(
|
|
||||||
this.spec()
|
|
||||||
.must(() -> this.isValidGuid(item))
|
|
||||||
.failOn("uuid").failWith(messageSource.getMessage("Validation_Required", new Object[]{"uuid"}, LocaleContextHolder.getLocale()))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,41 +0,0 @@
|
||||||
package gr.cite.annotation.convention;
|
|
||||||
|
|
||||||
import gr.cite.tools.exception.MyApplicationException;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.UUID;
|
|
||||||
import java.util.function.Function;
|
|
||||||
|
|
||||||
public interface ConventionService {
|
|
||||||
Boolean isValidId(Integer id);
|
|
||||||
|
|
||||||
Boolean isValidGuid(UUID guid);
|
|
||||||
|
|
||||||
Boolean isValidUUID(String str);
|
|
||||||
UUID parseUUIDSafe(String str);
|
|
||||||
|
|
||||||
Boolean isValidHash(String hash);
|
|
||||||
|
|
||||||
String hashValue(Object value) throws MyApplicationException;
|
|
||||||
|
|
||||||
String limit(String text, int maxLength);
|
|
||||||
|
|
||||||
String truncate(String text, int maxLength);
|
|
||||||
|
|
||||||
UUID getEmptyUUID();
|
|
||||||
|
|
||||||
boolean isNullOrEmpty(String value);
|
|
||||||
|
|
||||||
boolean isListNullOrEmpty(List value);
|
|
||||||
|
|
||||||
String stringEmpty();
|
|
||||||
|
|
||||||
String asPrefix(String name);
|
|
||||||
|
|
||||||
String asIndexerPrefix(String part);
|
|
||||||
|
|
||||||
String asIndexer(String... names);
|
|
||||||
|
|
||||||
<K, V> Map<K, List<V>> toDictionaryOfList(List<V> items, Function<V, K> keySelector);
|
|
||||||
}
|
|
|
@ -1,150 +0,0 @@
|
||||||
package gr.cite.annotation.convention;
|
|
||||||
|
|
||||||
import gr.cite.annotation.errorcode.ErrorThesaurusProperties;
|
|
||||||
import gr.cite.tools.exception.MyApplicationException;
|
|
||||||
import gr.cite.tools.logging.LoggerService;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
|
|
||||||
import org.springframework.context.annotation.Scope;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
|
|
||||||
import java.time.Instant;
|
|
||||||
import java.util.*;
|
|
||||||
import java.util.function.Function;
|
|
||||||
import java.util.regex.Pattern;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
@Component
|
|
||||||
@Scope(value = ConfigurableBeanFactory.SCOPE_SINGLETON)
|
|
||||||
public class ConventionServiceImpl implements ConventionService {
|
|
||||||
private final static Pattern UUID_REGEX_PATTERN = Pattern.compile("^[{]?[0-9a-fA-F]{8}-([0-9a-fA-F]{4}-){3}[0-9a-fA-F]{12}[}]?$");
|
|
||||||
|
|
||||||
private static final LoggerService logger = new LoggerService(LoggerFactory.getLogger(ConventionServiceImpl.class));
|
|
||||||
private final ErrorThesaurusProperties errors;
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
public ConventionServiceImpl(ErrorThesaurusProperties errors) {
|
|
||||||
this.errors = errors;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Boolean isValidId(Integer id) {
|
|
||||||
return id != null && id > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Boolean isValidGuid(UUID guid) {
|
|
||||||
return guid != null && !guid.equals(this.getEmptyUUID());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Boolean isValidUUID(String str) {
|
|
||||||
if (this.isNullOrEmpty(str)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return UUID_REGEX_PATTERN.matcher(str).matches();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public UUID parseUUIDSafe(String str) {
|
|
||||||
if (!this.isValidUUID(str)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
return UUID.fromString(str);
|
|
||||||
} catch (Exception ex){
|
|
||||||
logger.warn("invalid uuid" + str, ex);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Boolean isValidHash(String hash) {
|
|
||||||
return !this.isNullOrEmpty(hash);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String hashValue(Object value) throws MyApplicationException {
|
|
||||||
if (value == null) return this.stringEmpty();
|
|
||||||
if (value instanceof Instant) return String.format("%ts", (Instant) value);
|
|
||||||
throw new MyApplicationException(this.errors.getSystemError().getCode(), this.errors.getSystemError().getMessage());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String limit(String text, int maxLength) {
|
|
||||||
if (this.isNullOrEmpty(text)) return text;
|
|
||||||
if (text.length() > maxLength) return String.format("%s...", text.substring(0, maxLength));
|
|
||||||
else return text;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String truncate(String text, int maxLength) {
|
|
||||||
String truncated = text;
|
|
||||||
if (text.length() < maxLength) return text;
|
|
||||||
|
|
||||||
truncated = truncated.trim();
|
|
||||||
truncated = truncated.replaceAll("\\s+", " ");//remove multiple spaces
|
|
||||||
if (truncated.length() < maxLength) return truncated;
|
|
||||||
truncated = truncated.replaceAll("([.!@#$%^&-=':;,<>?*\\\"/|])+", "");//remove multiple spaces
|
|
||||||
if (truncated.length() < maxLength) return truncated;
|
|
||||||
truncated = truncated.replaceAll("([aeiou])+", "");//remove multiple spaces
|
|
||||||
if (truncated.length() < maxLength) return truncated;
|
|
||||||
truncated = truncated.replaceAll("([AEIOU])+", "");//remove multiple spaces
|
|
||||||
if (truncated.length() < maxLength) return truncated;
|
|
||||||
|
|
||||||
if (text.length() > maxLength) return String.format("%s...", text.substring(0, maxLength));
|
|
||||||
return text;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public UUID getEmptyUUID() {
|
|
||||||
return new UUID(0L, 0L);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isNullOrEmpty(String value) {
|
|
||||||
return value == null || value.isBlank();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isListNullOrEmpty(List value) {
|
|
||||||
if(value == null) return true;
|
|
||||||
return value.size() <= 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String stringEmpty() {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String asPrefix(String name) {
|
|
||||||
if (name == null) return null;
|
|
||||||
return name + ".";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String asIndexer(String... names) {
|
|
||||||
if (names == null) return null;
|
|
||||||
return String.join(".", Arrays.stream(names).filter(x -> !this.isNullOrEmpty(x)).collect(Collectors.toList()));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String asIndexerPrefix(String part) {
|
|
||||||
if (part == null) return null;
|
|
||||||
return part + ".";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public <K, V> Map<K, List<V>> toDictionaryOfList(List<V> items, Function<V, K> keySelector) {
|
|
||||||
Map<K, List<V>> map = new HashMap<>();
|
|
||||||
for (V model : items) {
|
|
||||||
K key = keySelector.apply(model);
|
|
||||||
if (!map.containsKey(key)) map.put(key, new ArrayList<V>());
|
|
||||||
map.get(key).add(model);
|
|
||||||
}
|
|
||||||
return map;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,188 +0,0 @@
|
||||||
package gr.cite.annotation.data;
|
|
||||||
|
|
||||||
import gr.cite.annotation.common.enums.AnnotationProtectionType;
|
|
||||||
import gr.cite.annotation.common.enums.IsActive;
|
|
||||||
import gr.cite.annotation.data.conventers.AnnotationProtectionTypeConverter;
|
|
||||||
import gr.cite.annotation.data.conventers.IsActiveConverter;
|
|
||||||
import gr.cite.annotation.data.tenant.TenantScopedBaseEntity;
|
|
||||||
import jakarta.persistence.*;
|
|
||||||
|
|
||||||
import java.time.Instant;
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
@Entity
|
|
||||||
@Table(name = "\"Annotation\"")
|
|
||||||
public class AnnotationEntity extends TenantScopedBaseEntity {
|
|
||||||
|
|
||||||
@Id
|
|
||||||
@Column(name = "id", columnDefinition = "uuid", updatable = false, nullable = false)
|
|
||||||
private UUID id;
|
|
||||||
|
|
||||||
public static final String _id = "id";
|
|
||||||
|
|
||||||
@Column(name = "entity_id", columnDefinition = "uuid", nullable = false)
|
|
||||||
private UUID entityId;
|
|
||||||
|
|
||||||
public static final String _entityId = "entityId";
|
|
||||||
|
|
||||||
@Column(name = "entity_type", nullable = false)
|
|
||||||
private String entityType;
|
|
||||||
|
|
||||||
public static final String _entityType = "entityType";
|
|
||||||
|
|
||||||
@Column(name = "anchor")
|
|
||||||
private String anchor;
|
|
||||||
|
|
||||||
public static final String _anchor = "anchor";
|
|
||||||
|
|
||||||
@Column(name = "payload", nullable = false)
|
|
||||||
private String payload;
|
|
||||||
|
|
||||||
public static final String _payload = "payload";
|
|
||||||
|
|
||||||
@Column(name = "subject_id", columnDefinition = "uuid", nullable = false)
|
|
||||||
private UUID subjectId;
|
|
||||||
|
|
||||||
public static final String _subjectId = "subjectId";
|
|
||||||
|
|
||||||
@Column(name = "thread_id", columnDefinition = "uuid")
|
|
||||||
private UUID threadId;
|
|
||||||
|
|
||||||
public static final String _threadId = "threadId";
|
|
||||||
|
|
||||||
@Column(name = "parent_id", columnDefinition = "uuid")
|
|
||||||
private UUID parentId;
|
|
||||||
|
|
||||||
public static final String _parentId = "parentId";
|
|
||||||
|
|
||||||
@Column(name = "protection_type", nullable = false)
|
|
||||||
@Convert(converter = AnnotationProtectionTypeConverter.class)
|
|
||||||
private AnnotationProtectionType protectionType;
|
|
||||||
|
|
||||||
public static final String _protectionType = "protectionType";
|
|
||||||
|
|
||||||
@Column(name = "time_stamp", nullable = false)
|
|
||||||
private Instant timeStamp;
|
|
||||||
|
|
||||||
public static final String _timeStamp = "timeStamp";
|
|
||||||
|
|
||||||
@Column(name = "\"created_at\"", nullable = false)
|
|
||||||
private Instant createdAt;
|
|
||||||
|
|
||||||
public static final String _createdAt = "createdAt";
|
|
||||||
|
|
||||||
@Column(name = "\"updated_at\"", nullable = false)
|
|
||||||
private Instant updatedAt;
|
|
||||||
|
|
||||||
public static final String _updatedAt = "updatedAt";
|
|
||||||
|
|
||||||
@Column(name = "is_active", nullable = false)
|
|
||||||
@Convert(converter = IsActiveConverter.class)
|
|
||||||
private IsActive isActive;
|
|
||||||
|
|
||||||
public static final String _isActive = "isActive";
|
|
||||||
|
|
||||||
public UUID getId() {
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setId(UUID id) {
|
|
||||||
this.id = id;
|
|
||||||
}
|
|
||||||
|
|
||||||
public UUID getEntityId() {
|
|
||||||
return entityId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setEntityId(UUID entityId) {
|
|
||||||
this.entityId = entityId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getEntityType() {
|
|
||||||
return entityType;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setEntityType(String entityType) {
|
|
||||||
this.entityType = entityType;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getAnchor() {
|
|
||||||
return anchor;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setAnchor(String anchor) {
|
|
||||||
this.anchor = anchor;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getPayload() {
|
|
||||||
return payload;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setPayload(String payload) {
|
|
||||||
this.payload = payload;
|
|
||||||
}
|
|
||||||
|
|
||||||
public UUID getSubjectId() {
|
|
||||||
return subjectId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setSubjectId(UUID subjectId) {
|
|
||||||
this.subjectId = subjectId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public UUID getThreadId() {
|
|
||||||
return threadId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setThreadId(UUID threadId) {
|
|
||||||
this.threadId = threadId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public UUID getParentId() {
|
|
||||||
return parentId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setParentId(UUID parentId) {
|
|
||||||
this.parentId = parentId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Instant getTimeStamp() {
|
|
||||||
return timeStamp;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setTimeStamp(Instant timeStamp) {
|
|
||||||
this.timeStamp = timeStamp;
|
|
||||||
}
|
|
||||||
|
|
||||||
public AnnotationProtectionType getProtectionType() {
|
|
||||||
return protectionType;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setProtectionType(AnnotationProtectionType protectionType) {
|
|
||||||
this.protectionType = protectionType;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Instant getCreatedAt() {
|
|
||||||
return createdAt;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setCreatedAt(Instant createdAt) {
|
|
||||||
this.createdAt = createdAt;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Instant getUpdatedAt() {
|
|
||||||
return updatedAt;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setUpdatedAt(Instant updatedAt) {
|
|
||||||
this.updatedAt = updatedAt;
|
|
||||||
}
|
|
||||||
|
|
||||||
public IsActive getIsActive() {
|
|
||||||
return isActive;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setIsActive(IsActive isActive) {
|
|
||||||
this.isActive = isActive;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,94 +0,0 @@
|
||||||
package gr.cite.annotation.data;
|
|
||||||
|
|
||||||
import gr.cite.annotation.common.enums.IsActive;
|
|
||||||
import gr.cite.annotation.data.conventers.IsActiveConverter;
|
|
||||||
import gr.cite.annotation.data.tenant.TenantScopedBaseEntity;
|
|
||||||
import jakarta.persistence.*;
|
|
||||||
|
|
||||||
import java.time.Instant;
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
@Entity
|
|
||||||
@Table(name = "\"EntityUser\"")
|
|
||||||
public class EntityUserEntity extends TenantScopedBaseEntity {
|
|
||||||
|
|
||||||
@Id
|
|
||||||
@Column(name = "\"id\"", columnDefinition = "uuid", updatable = false, nullable = false)
|
|
||||||
private UUID id;
|
|
||||||
|
|
||||||
public static final String _id = "id";
|
|
||||||
|
|
||||||
@Column(name = "\"entity_id\"", columnDefinition = "uuid", nullable = false)
|
|
||||||
private UUID entityId;
|
|
||||||
|
|
||||||
public static final String _entityId = "entityId";
|
|
||||||
|
|
||||||
@Column(name = "\"user_id\"", columnDefinition = "uuid", nullable = false)
|
|
||||||
private UUID userId;
|
|
||||||
|
|
||||||
public static final String _userId = "userId";
|
|
||||||
|
|
||||||
@Column(name = "\"created_at\"", nullable = false)
|
|
||||||
private Instant createdAt;
|
|
||||||
|
|
||||||
public static final String _createdAt = "createdAt";
|
|
||||||
|
|
||||||
@Column(name = "\"updated_at\"", nullable = false)
|
|
||||||
private Instant updatedAt;
|
|
||||||
|
|
||||||
public static final String _updatedAt = "updatedAt";
|
|
||||||
|
|
||||||
@Column(name = "is_active", nullable = false)
|
|
||||||
@Convert(converter = IsActiveConverter.class)
|
|
||||||
private IsActive isActive;
|
|
||||||
|
|
||||||
public static final String _isActive = "isActive";
|
|
||||||
|
|
||||||
public UUID getId() {
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setId(UUID id) {
|
|
||||||
this.id = id;
|
|
||||||
}
|
|
||||||
|
|
||||||
public UUID getEntityId() {
|
|
||||||
return entityId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setEntityId(UUID entityId) {
|
|
||||||
this.entityId = entityId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public UUID getUserId() {
|
|
||||||
return userId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setUserId(UUID userId) {
|
|
||||||
this.userId = userId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Instant getCreatedAt() {
|
|
||||||
return createdAt;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setCreatedAt(Instant createdAt) {
|
|
||||||
this.createdAt = createdAt;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Instant getUpdatedAt() {
|
|
||||||
return updatedAt;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setUpdatedAt(Instant updatedAt) {
|
|
||||||
this.updatedAt = updatedAt;
|
|
||||||
}
|
|
||||||
|
|
||||||
public IsActive getIsActive() {
|
|
||||||
return isActive;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setIsActive(IsActive isActive) {
|
|
||||||
this.isActive = isActive;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,195 +0,0 @@
|
||||||
package gr.cite.annotation.data;
|
|
||||||
|
|
||||||
import gr.cite.annotation.common.enums.IsActive;
|
|
||||||
import gr.cite.annotation.data.conventers.IsActiveConverter;
|
|
||||||
import gr.cite.annotation.data.conventers.QueueInboxStatusConverter;
|
|
||||||
import gr.cite.annotation.data.types.JsonSQLType;
|
|
||||||
import gr.cite.queueinbox.entity.QueueInbox;
|
|
||||||
import gr.cite.queueinbox.entity.QueueInboxStatus;
|
|
||||||
import jakarta.persistence.*;
|
|
||||||
import org.hibernate.annotations.Type;
|
|
||||||
|
|
||||||
import java.time.Instant;
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
@Entity
|
|
||||||
@Table(name = "\"QueueInbox\"")
|
|
||||||
public class QueueInboxEntity implements QueueInbox {
|
|
||||||
|
|
||||||
@Id
|
|
||||||
@Column(name = "\"id\"", columnDefinition = "uuid", updatable = false, nullable = false)
|
|
||||||
private UUID id;
|
|
||||||
|
|
||||||
public static final String _id = "id";
|
|
||||||
|
|
||||||
@Column(name = "\"queue\"", nullable = false, length = 200)
|
|
||||||
private String queue;
|
|
||||||
|
|
||||||
public static final String _queue = "queue";
|
|
||||||
|
|
||||||
@Column(name = "\"exchange\"", nullable = false, length = 200)
|
|
||||||
private String exchange;
|
|
||||||
|
|
||||||
public static final String _exchange = "exchange";
|
|
||||||
|
|
||||||
@Column(name = "\"route\"", nullable = false, length = 200)
|
|
||||||
private String route;
|
|
||||||
|
|
||||||
public static final String _route = "route";
|
|
||||||
|
|
||||||
@Column(name = "\"application_id\"", nullable = false, length = 100)
|
|
||||||
private String applicationId;
|
|
||||||
|
|
||||||
public static final String _applicationId = "applicationId";
|
|
||||||
|
|
||||||
@Column(name = "\"message_id\"", columnDefinition = "uuid", nullable = false)
|
|
||||||
private UUID messageId;
|
|
||||||
|
|
||||||
public static final String _messageId = "messageId";
|
|
||||||
|
|
||||||
@Type(JsonSQLType.class)
|
|
||||||
@Column(name = "\"message\"", columnDefinition = "json", nullable = false)
|
|
||||||
private String message;
|
|
||||||
|
|
||||||
public static final String _message = "message";
|
|
||||||
|
|
||||||
@Column(name = "\"retry_count\"")
|
|
||||||
private Integer retryCount;
|
|
||||||
|
|
||||||
public static final String _retryCount = "retryCount";
|
|
||||||
|
|
||||||
@Column(name = "\"tenant\"", columnDefinition = "uuid")
|
|
||||||
private UUID tenantId;
|
|
||||||
|
|
||||||
public static final String _tenantId = "tenantId";
|
|
||||||
|
|
||||||
@Column(name = "\"status\"", nullable = false)
|
|
||||||
@Convert(converter = QueueInboxStatusConverter.class)
|
|
||||||
private QueueInboxStatus status;
|
|
||||||
public final static String _status = "status";
|
|
||||||
|
|
||||||
|
|
||||||
@Column(name = "\"created_at\"", nullable = false)
|
|
||||||
private Instant createdAt;
|
|
||||||
|
|
||||||
public static final String _createdAt = "createdAt";
|
|
||||||
|
|
||||||
@Column(name = "\"updated_at\"", nullable = false)
|
|
||||||
@Version
|
|
||||||
private Instant updatedAt;
|
|
||||||
|
|
||||||
public static final String _updatedAt = "updatedAt";
|
|
||||||
|
|
||||||
@Column(name = "\"is_active\"", nullable = false)
|
|
||||||
@Convert(converter = IsActiveConverter.class)
|
|
||||||
private IsActive isActive;
|
|
||||||
|
|
||||||
public static final String _isActive = "isActive";
|
|
||||||
|
|
||||||
public UUID getId() {
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setId(UUID id) {
|
|
||||||
this.id = id;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getQueue() {
|
|
||||||
return queue;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setQueue(String queue) {
|
|
||||||
this.queue = queue;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getExchange() {
|
|
||||||
return exchange;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setExchange(String exchange) {
|
|
||||||
this.exchange = exchange;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getRoute() {
|
|
||||||
return route;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setRoute(String route) {
|
|
||||||
this.route = route;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getApplicationId() {
|
|
||||||
return applicationId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setApplicationId(String applicationId) {
|
|
||||||
this.applicationId = applicationId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public UUID getMessageId() {
|
|
||||||
return messageId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setMessageId(UUID messageId) {
|
|
||||||
this.messageId = messageId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getMessage() {
|
|
||||||
return message;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setMessage(String message) {
|
|
||||||
this.message = message;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Integer getRetryCount() {
|
|
||||||
return retryCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setRetryCount(Integer retryCount) {
|
|
||||||
this.retryCount = retryCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
public UUID getTenantId() {
|
|
||||||
return tenantId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setTenantId(UUID tenantId) {
|
|
||||||
this.tenantId = tenantId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public QueueInboxStatus getStatus() {
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setStatus(QueueInboxStatus status) {
|
|
||||||
this.status = status;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Instant getCreatedAt() {
|
|
||||||
return createdAt;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setCreatedAt(Instant createdAt) {
|
|
||||||
this.createdAt = createdAt;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Instant getUpdatedAt() {
|
|
||||||
return updatedAt;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setUpdatedAt(Instant updatedAt) {
|
|
||||||
this.updatedAt = updatedAt;
|
|
||||||
}
|
|
||||||
|
|
||||||
public IsActive getIsActive() {
|
|
||||||
return isActive;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setIsActive(IsActive isActive) {
|
|
||||||
this.isActive = isActive;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,206 +0,0 @@
|
||||||
package gr.cite.annotation.data;
|
|
||||||
|
|
||||||
import gr.cite.annotation.common.enums.IsActive;
|
|
||||||
import gr.cite.annotation.data.conventers.IsActiveConverter;
|
|
||||||
import gr.cite.annotation.data.conventers.QueueOutboxNotifyStatusConverter;
|
|
||||||
import gr.cite.queueoutbox.entity.QueueOutbox;
|
|
||||||
import gr.cite.queueoutbox.entity.QueueOutboxNotifyStatus;
|
|
||||||
import jakarta.persistence.*;
|
|
||||||
|
|
||||||
import java.time.Instant;
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
@Entity
|
|
||||||
@Table(name = "\"QueueOutbox\"")
|
|
||||||
public class QueueOutboxEntity implements QueueOutbox {
|
|
||||||
|
|
||||||
@Id
|
|
||||||
@Column(name = "\"id\"", columnDefinition = "uuid", updatable = false, nullable = false)
|
|
||||||
private UUID id;
|
|
||||||
|
|
||||||
public static final String _id = "id";
|
|
||||||
|
|
||||||
@Column(name = "\"exchange\"", nullable = false, length = 200)
|
|
||||||
private String exchange;
|
|
||||||
|
|
||||||
public static final String _exchange = "exchange";
|
|
||||||
|
|
||||||
@Column(name = "\"route\"", length = 200)
|
|
||||||
private String route;
|
|
||||||
|
|
||||||
public static final String _route = "route";
|
|
||||||
|
|
||||||
@Column(name = "\"message_id\"", columnDefinition = "uuid", nullable = false)
|
|
||||||
private UUID messageId;
|
|
||||||
|
|
||||||
public static final String _messageId = "messageId";
|
|
||||||
|
|
||||||
@Column(name = "\"message\"", columnDefinition = "json", nullable = false)
|
|
||||||
private String message;
|
|
||||||
|
|
||||||
public static final String _message = "message";
|
|
||||||
|
|
||||||
@Column(name = "\"notify_status\"", nullable = false)
|
|
||||||
@Convert(converter = QueueOutboxNotifyStatusConverter.class)
|
|
||||||
private QueueOutboxNotifyStatus notifyStatus;
|
|
||||||
public final static String _notifyStatus = "notifyStatus";
|
|
||||||
|
|
||||||
@Column(name = "\"retry_count\"", nullable = false)
|
|
||||||
private Integer retryCount;
|
|
||||||
|
|
||||||
public static final String _retryCount = "retryCount";
|
|
||||||
|
|
||||||
@Column(name = "\"published_at\"")
|
|
||||||
private Instant publishedAt;
|
|
||||||
|
|
||||||
public static final String _publishedAt = "publishedAt";
|
|
||||||
|
|
||||||
@Column(name = "\"confirmed_at\"")
|
|
||||||
private Instant confirmedAt;
|
|
||||||
|
|
||||||
public static final String _confirmedAt = "confirmedAt";
|
|
||||||
|
|
||||||
@Column(name = "\"tenant\"", columnDefinition = "uuid")
|
|
||||||
private UUID tenantId;
|
|
||||||
|
|
||||||
public static final String _tenantId = "tenantId";
|
|
||||||
|
|
||||||
@Column(name = "\"created_at\"", nullable = false)
|
|
||||||
private Instant createdAt;
|
|
||||||
|
|
||||||
public static final String _createdAt = "createdAt";
|
|
||||||
|
|
||||||
@Column(name = "\"updated_at\"", nullable = false)
|
|
||||||
@Version
|
|
||||||
private Instant updatedAt;
|
|
||||||
|
|
||||||
public static final String _updatedAt = "updatedAt";
|
|
||||||
|
|
||||||
@Column(name = "\"is_active\"", length = 20, nullable = false)
|
|
||||||
@Convert(converter = IsActiveConverter.class)
|
|
||||||
private IsActive isActive;
|
|
||||||
|
|
||||||
public static final String _isActive = "isActive";
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public UUID getId() {
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setId(UUID id) {
|
|
||||||
this.id = id;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getExchange() {
|
|
||||||
return exchange;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setExchange(String exchange) {
|
|
||||||
this.exchange = exchange;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getRoute() {
|
|
||||||
return route;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setRoute(String route) {
|
|
||||||
this.route = route;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public UUID getMessageId() {
|
|
||||||
return messageId;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setMessageId(UUID messageId) {
|
|
||||||
this.messageId = messageId;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getMessage() {
|
|
||||||
return message;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setMessage(String message) {
|
|
||||||
this.message = message;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public QueueOutboxNotifyStatus getNotifyStatus() {
|
|
||||||
return notifyStatus;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setNotifyStatus(QueueOutboxNotifyStatus notifyStatus) {
|
|
||||||
this.notifyStatus = notifyStatus;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Integer getRetryCount() {
|
|
||||||
return retryCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setRetryCount(Integer retryCount) {
|
|
||||||
this.retryCount = retryCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Instant getPublishedAt() {
|
|
||||||
return publishedAt;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setPublishedAt(Instant publishedAt) {
|
|
||||||
this.publishedAt = publishedAt;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Instant getConfirmedAt() {
|
|
||||||
return confirmedAt;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setConfirmedAt(Instant confirmedAt) {
|
|
||||||
this.confirmedAt = confirmedAt;
|
|
||||||
}
|
|
||||||
|
|
||||||
public UUID getTenantId() {
|
|
||||||
return tenantId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setTenantId(UUID tenantId) {
|
|
||||||
this.tenantId = tenantId;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Instant getCreatedAt() {
|
|
||||||
return createdAt;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setCreatedAt(Instant createdAt) {
|
|
||||||
this.createdAt = createdAt;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Instant getUpdatedAt() {
|
|
||||||
return updatedAt;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setUpdatedAt(Instant updatedAt) {
|
|
||||||
this.updatedAt = updatedAt;
|
|
||||||
}
|
|
||||||
|
|
||||||
public IsActive getIsActive() {
|
|
||||||
return isActive;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setIsActive(IsActive isActive) {
|
|
||||||
this.isActive = isActive;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,81 +0,0 @@
|
||||||
package gr.cite.annotation.data;
|
|
||||||
|
|
||||||
import gr.cite.annotation.common.enums.IsActive;
|
|
||||||
import gr.cite.annotation.data.conventers.IsActiveConverter;
|
|
||||||
import jakarta.persistence.*;
|
|
||||||
|
|
||||||
import java.time.Instant;
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
@Entity
|
|
||||||
@Table(name = "\"Tenant\"")
|
|
||||||
public class TenantEntity {
|
|
||||||
|
|
||||||
@Id
|
|
||||||
@Column(name = "id", columnDefinition = "uuid", updatable = false, nullable = false)
|
|
||||||
private UUID id;
|
|
||||||
|
|
||||||
public static final String _id = "id";
|
|
||||||
|
|
||||||
@Column(name = "code", length = 200, nullable = false)
|
|
||||||
private String code;
|
|
||||||
|
|
||||||
public static final String _code = "code";
|
|
||||||
|
|
||||||
@Column(name = "created_at", nullable = false)
|
|
||||||
private Instant createdAt;
|
|
||||||
|
|
||||||
public static final String _createdAt = "createdAt";
|
|
||||||
|
|
||||||
@Column(name = "updated_at", nullable = false)
|
|
||||||
private Instant updatedAt;
|
|
||||||
|
|
||||||
public static final String _updatedAt = "updatedAt";
|
|
||||||
|
|
||||||
@Column(name = "is_active", length = 20, nullable = false)
|
|
||||||
@Convert(converter = IsActiveConverter.class)
|
|
||||||
private IsActive isActive;
|
|
||||||
|
|
||||||
public static final String _isActive = "isActive";
|
|
||||||
|
|
||||||
public UUID getId() {
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setId(UUID id) {
|
|
||||||
this.id = id;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getCode() {
|
|
||||||
return code;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setCode(String code) {
|
|
||||||
this.code = code;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Instant getCreatedAt() {
|
|
||||||
return createdAt;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setCreatedAt(Instant createdAt) {
|
|
||||||
this.createdAt = createdAt;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Instant getUpdatedAt() {
|
|
||||||
return updatedAt;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setUpdatedAt(Instant updatedAt) {
|
|
||||||
this.updatedAt = updatedAt;
|
|
||||||
}
|
|
||||||
|
|
||||||
public IsActive getIsActive() {
|
|
||||||
return isActive;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setIsActive(IsActive isActive) {
|
|
||||||
this.isActive = isActive;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,165 +0,0 @@
|
||||||
package gr.cite.annotation.data;
|
|
||||||
|
|
||||||
import gr.cite.annotation.common.scope.tenant.TenantScope;
|
|
||||||
import gr.cite.annotation.common.scope.tenant.TenantScoped;
|
|
||||||
import gr.cite.annotation.data.tenant.TenantScopedBaseEntity;
|
|
||||||
import gr.cite.annotation.errorcode.ErrorThesaurusProperties;
|
|
||||||
import gr.cite.tools.exception.MyForbiddenException;
|
|
||||||
import jakarta.persistence.EntityManager;
|
|
||||||
import jakarta.persistence.FlushModeType;
|
|
||||||
import jakarta.persistence.PersistenceContext;
|
|
||||||
import org.hibernate.Session;
|
|
||||||
import org.springframework.stereotype.Service;
|
|
||||||
import org.springframework.web.context.annotation.RequestScope;
|
|
||||||
|
|
||||||
import javax.management.InvalidApplicationException;
|
|
||||||
|
|
||||||
@Service
|
|
||||||
@RequestScope
|
|
||||||
public class TenantEntityManager {
|
|
||||||
@PersistenceContext
|
|
||||||
private EntityManager entityManager;
|
|
||||||
private final TenantScope tenantScope;
|
|
||||||
private final ErrorThesaurusProperties errors;
|
|
||||||
|
|
||||||
boolean tenantFiltersDisabled;
|
|
||||||
|
|
||||||
public TenantEntityManager(TenantScope tenantScope, ErrorThesaurusProperties errors) {
|
|
||||||
this.tenantScope = tenantScope;
|
|
||||||
this.errors = errors;
|
|
||||||
this.tenantFiltersDisabled = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void persist(Object entity) {
|
|
||||||
this.entityManager.persist(entity);
|
|
||||||
}
|
|
||||||
|
|
||||||
public <T> T merge(T entity) throws InvalidApplicationException {
|
|
||||||
if (!this.tenantFiltersDisabled && this.tenantScope.isMultitenant() && (entity instanceof TenantScoped tenantScopedEntity)) {
|
|
||||||
if (!this.tenantScope.isDefaultTenant()) {
|
|
||||||
if (tenantScopedEntity.getTenantId() == null || !tenantScopedEntity.getTenantId().equals(this.tenantScope.getTenant())) throw new MyForbiddenException(this.errors.getTenantTampering().getCode(), this.errors.getTenantTampering().getMessage());
|
|
||||||
} else if (tenantScopedEntity.getTenantId() != null) {
|
|
||||||
throw new MyForbiddenException(this.errors.getTenantTampering().getCode(), this.errors.getTenantTampering().getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return this.entityManager.merge(entity);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void remove(Object entity) throws InvalidApplicationException {
|
|
||||||
if (!this.tenantFiltersDisabled && this.tenantScope.isMultitenant() && (entity instanceof TenantScoped tenantScopedEntity)) {
|
|
||||||
if (!this.tenantScope.isDefaultTenant()) {
|
|
||||||
if (tenantScopedEntity.getTenantId() == null || !tenantScopedEntity.getTenantId().equals(this.tenantScope.getTenant())) throw new MyForbiddenException(this.errors.getTenantTampering().getCode(), this.errors.getTenantTampering().getMessage());
|
|
||||||
} else if (tenantScopedEntity.getTenantId() != null) {
|
|
||||||
throw new MyForbiddenException(this.errors.getTenantTampering().getCode(), this.errors.getTenantTampering().getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.entityManager.remove(entity);
|
|
||||||
}
|
|
||||||
|
|
||||||
public <T> T find(Class<T> entityClass, Object primaryKey) throws InvalidApplicationException {
|
|
||||||
T entity = this.entityManager.find(entityClass, primaryKey);
|
|
||||||
|
|
||||||
if (!this.tenantFiltersDisabled && this.tenantScope.isMultitenant() && (entity instanceof TenantScoped tenantScopedEntity)) {
|
|
||||||
if (tenantScopedEntity.getTenantId() != null && !tenantScopedEntity.getTenantId().equals(this.tenantScope.getTenant())) return null;
|
|
||||||
}
|
|
||||||
return entity;
|
|
||||||
}
|
|
||||||
|
|
||||||
public <T> T find(Class<T> entityClass, Object primaryKey, boolean disableTracking) throws InvalidApplicationException {
|
|
||||||
T entity = this.entityManager.find(entityClass, primaryKey);
|
|
||||||
|
|
||||||
if (!this.tenantFiltersDisabled && this.tenantScope.isMultitenant() && (entity instanceof TenantScoped tenantScopedEntity)) {
|
|
||||||
if (tenantScopedEntity.getTenantId() != null && !tenantScopedEntity.getTenantId().equals(this.tenantScope.getTenant())) return null;
|
|
||||||
}
|
|
||||||
if (disableTracking) this.entityManager.detach(entity);
|
|
||||||
return entity;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void flush() {
|
|
||||||
this.entityManager.flush();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void setFlushMode(FlushModeType flushMode) {
|
|
||||||
this.entityManager.setFlushMode(flushMode);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public FlushModeType getFlushMode() {
|
|
||||||
return this.entityManager.getFlushMode();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void clear() {
|
|
||||||
this.entityManager.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void reloadTenantFilters() throws InvalidApplicationException {
|
|
||||||
if (!this.entityManager.isOpen()) return;
|
|
||||||
|
|
||||||
this.disableTenantFilters();
|
|
||||||
|
|
||||||
if (!this.tenantScope.isSet()) return;
|
|
||||||
|
|
||||||
if (!this.tenantScope.isDefaultTenant()) {
|
|
||||||
this.entityManager
|
|
||||||
.unwrap(Session.class)
|
|
||||||
.enableFilter(TenantScopedBaseEntity.TENANT_FILTER)
|
|
||||||
.setParameter(TenantScopedBaseEntity.TENANT_FILTER_TENANT_PARAM, this.tenantScope.getTenant().toString());
|
|
||||||
} else {
|
|
||||||
this.entityManager
|
|
||||||
.unwrap(Session.class)
|
|
||||||
.enableFilter(TenantScopedBaseEntity.DEFAULT_TENANT_FILTER);
|
|
||||||
}
|
|
||||||
this.tenantFiltersDisabled = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void loadExplictTenantFilters() throws InvalidApplicationException {
|
|
||||||
if (!this.entityManager.isOpen()) return;
|
|
||||||
|
|
||||||
this.disableTenantFilters();
|
|
||||||
|
|
||||||
if (!this.tenantScope.isSet()) return;
|
|
||||||
|
|
||||||
if (!this.tenantScope.isDefaultTenant()) {
|
|
||||||
this.entityManager
|
|
||||||
.unwrap(Session.class)
|
|
||||||
.enableFilter(TenantScopedBaseEntity.TENANT_FILTER_EXPLICT)
|
|
||||||
.setParameter(TenantScopedBaseEntity.TENANT_FILTER_TENANT_PARAM, this.tenantScope.getTenant().toString());
|
|
||||||
} else {
|
|
||||||
this.entityManager
|
|
||||||
.unwrap(Session.class)
|
|
||||||
.enableFilter(TenantScopedBaseEntity.DEFAULT_TENANT_FILTER);
|
|
||||||
}
|
|
||||||
this.tenantFiltersDisabled = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void disableTenantFilters() {
|
|
||||||
if (!this.entityManager.isOpen()) return;
|
|
||||||
|
|
||||||
this.entityManager
|
|
||||||
.unwrap(Session.class)
|
|
||||||
.disableFilter(TenantScopedBaseEntity.TENANT_FILTER);
|
|
||||||
|
|
||||||
this.entityManager
|
|
||||||
.unwrap(Session.class)
|
|
||||||
.disableFilter(TenantScopedBaseEntity.DEFAULT_TENANT_FILTER);
|
|
||||||
|
|
||||||
this.entityManager
|
|
||||||
.unwrap(Session.class)
|
|
||||||
.disableFilter(TenantScopedBaseEntity.TENANT_FILTER_EXPLICT);
|
|
||||||
this.tenantFiltersDisabled = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isTenantFiltersDisabled() {
|
|
||||||
return this.tenantFiltersDisabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
public EntityManager getEntityManager() {
|
|
||||||
return this.entityManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setEntityManager(EntityManager entityManager) {
|
|
||||||
this.entityManager = entityManager;
|
|
||||||
}
|
|
||||||
}
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue