Skip to content

Commit

Permalink
Merge pull request #79 from xm-online/feature/service_not_found_and_n…
Browse files Browse the repository at this point in the history
…ot_active

Add servce not found and not active
  • Loading branch information
sergeysenja1992 committed Apr 2, 2024
2 parents 225aff5 + 464a476 commit 686d776
Show file tree
Hide file tree
Showing 7 changed files with 143 additions and 7 deletions.
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
rootProject.name=gate
profile=dev
version=2.1.14
version=2.1.15

# Build properties
node_version=12.13.0
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ public class ApplicationProperties {
private String tenantPropertiesName;
private Boolean disableIdpCookieUsage;

private Boolean redirectToDefaultTenantEnabled;

@Getter
@Setter
private static class Retry {
Expand Down
40 changes: 37 additions & 3 deletions src/main/java/com/icthh/xm/gate/gateway/TenantInitFilter.java
Original file line number Diff line number Diff line change
@@ -1,22 +1,29 @@
package com.icthh.xm.gate.gateway;

import static com.icthh.xm.gate.config.Constants.FILTER_ORDER_TENANT_INIT;

import com.icthh.xm.commons.tenant.TenantContextHolder;
import com.icthh.xm.commons.tenant.TenantContextUtils;
import com.icthh.xm.gate.config.ApplicationProperties;
import com.icthh.xm.gate.service.TenantMappingService;
import lombok.AllArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

import static com.icthh.xm.gate.config.Constants.DEFAULT_TENANT;
import static com.icthh.xm.gate.config.Constants.FILTER_ORDER_TENANT_INIT;
import static javax.servlet.http.HttpServletResponse.SC_BAD_REQUEST;
import static org.springframework.http.HttpHeaders.LOCATION;

/**
* Filter for setting {@link TenantContextHolder}.
Expand All @@ -29,6 +36,7 @@ public class TenantInitFilter implements Filter {

private final TenantMappingService tenantMappingService;
private final TenantContextHolder tenantContextHolder;
private final ApplicationProperties applicationProperties;

@Override
public void init(FilterConfig filterConfig) throws ServletException {
Expand All @@ -41,6 +49,18 @@ public void doFilter(ServletRequest servletRequest, ServletResponse servletRespo
String domain = servletRequest.getServerName();
String tenantKeyValue = tenantMappingService.getTenantKey(domain);

if (!tenantMappingService.isTenantPresent(tenantKeyValue) && !DEFAULT_TENANT.equalsIgnoreCase(tenantKeyValue)) {
log.error("Tenant {} is not present", tenantKeyValue);
response(servletResponse, "SERVICE-NOT-FOUND");
return;
}

if (!tenantMappingService.isTenantActive(tenantKeyValue) && !DEFAULT_TENANT.equalsIgnoreCase(tenantKeyValue)) {
log.error("Tenant {} is not active", tenantKeyValue);
response(servletResponse, "SERVICE-SUSPENDED");
return;
}

TenantContextUtils.setTenant(tenantContextHolder, tenantKeyValue);
try {
filterChain.doFilter(servletRequest, servletResponse);
Expand All @@ -49,6 +69,20 @@ public void doFilter(ServletRequest servletRequest, ServletResponse servletRespo
}
}

@SneakyThrows
private static void response(ServletResponse servletResponse, String code) {
HttpServletResponse httpResponse = (HttpServletResponse) servletResponse;
httpResponse.setStatus(HttpServletResponse.SC_BAD_REQUEST);
httpResponse.setContentType("application/json");
httpResponse.setCharacterEncoding("UTF-8");

String jsonContent = "{\"error\": \"" + code + "\"}";

PrintWriter out = httpResponse.getWriter();
out.print(jsonContent);
out.flush();
}

@Override
public void destroy() {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,8 @@ public interface TenantMappingService extends RefreshableConfiguration {
Map<String, String> getTenantByDomain();

String getTenantKey(String domain);

boolean isTenantPresent(String tenantName);

boolean isTenantActive(String tenantName);
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import static com.fasterxml.jackson.databind.type.TypeFactory.defaultInstance;
import static com.icthh.xm.gate.config.Constants.DEFAULT_TENANT;
import static java.lang.Boolean.TRUE;
import static java.util.Collections.emptySet;
import static java.util.Collections.unmodifiableList;

Expand Down Expand Up @@ -31,18 +32,22 @@ public class TenantMappingServiceImpl implements TenantMappingService {

private static final String IP_REGEX = "\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}";
public static final String TENANTS_LIST_CONFIG_KEY = "/config/tenants/tenants-list.json";
public static final String ACTIVE = "ACTIVE";

private final List<String> hosts;
private final boolean redirectToDefaultTenantEnabled;
private final ObjectMapper objectMapper = new ObjectMapper();
private final String applicationName;

private volatile Map<String, String> tenantByDomain = new HashMap<>();
private volatile Map<String, Set<TenantState>> tenantsByServiceMap = new HashMap<>();

private final TenantDomainRepository tenantDomainRepository;

public TenantMappingServiceImpl(ApplicationProperties applicationProperties,
TenantDomainRepository tenantDomainRepository,
@Value("${spring.application.name}") String applicationName) {
this.redirectToDefaultTenantEnabled = TRUE.equals(applicationProperties.getRedirectToDefaultTenantEnabled());
this.hosts = unmodifiableList(applicationProperties.getHosts());
this.tenantDomainRepository = tenantDomainRepository;
this.applicationName = applicationName;
Expand All @@ -64,7 +69,7 @@ public String getTenantKey(final String domain) {
String tenantKey = Optional.ofNullable(tenantDomainRepository.getTenantKey(domain))
.orElse(getTenantByDomain().get(domain));

if (StringUtils.isBlank(tenantKey)) {
if ((StringUtils.isBlank(tenantKey) && redirectToDefaultTenantEnabled) || (domain.matches(IP_REGEX) || domain.equals("localhost"))) {
printWarnIfNotIpAddress(domain);
tenantKey = DEFAULT_TENANT;
}
Expand All @@ -86,6 +91,9 @@ private void updateTenants(String config) {
Map<String, Set<TenantState>> tenantsByServiceMap = objectMapper.readValue(config, type);

final Map<String, String> tenants = new HashMap<>();
for (String host : hosts) {
tenants.put(DEFAULT_TENANT.toLowerCase() + "." + host, DEFAULT_TENANT.toUpperCase());
}
for (TenantState tenant: tenantsByServiceMap.getOrDefault(applicationName, emptySet())) {
for (String host : hosts) {
tenants.put(tenant.getName().toLowerCase() + "." + host, tenant.getName().toUpperCase());
Expand All @@ -94,9 +102,25 @@ private void updateTenants(String config) {

log.info("Tenants sub-domain mapping configured by $application.hosts: {}", hosts);

this.tenantsByServiceMap = tenantsByServiceMap;
this.tenantByDomain = tenants;
}

@Override
public boolean isTenantPresent(String tenantName) {
return tenantsByServiceMap.getOrDefault(applicationName, emptySet())
.stream()
.anyMatch(tenant -> tenant.getName().equalsIgnoreCase(tenantName));
}

@Override
public boolean isTenantActive(String tenantName) {
return tenantsByServiceMap.getOrDefault(applicationName, emptySet())
.stream()
.filter(tenant -> tenant.getName().equalsIgnoreCase(tenantName))
.anyMatch(tenantState -> tenantState.getState().equals(ACTIVE));
}

@Override
public boolean isListeningConfiguration(String updatedKey) {
return TENANTS_LIST_CONFIG_KEY.equals(updatedKey);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package com.icthh.xm.gate.web.rest;

import com.icthh.xm.commons.config.client.repository.TenantListRepository;
import com.icthh.xm.gate.GateApp;
import com.icthh.xm.gate.config.SecurityBeanOverrideConfiguration;
import com.icthh.xm.gate.repository.TenantDomainRepository;
import com.icthh.xm.gate.service.TenantMappingService;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;

/**
*
*/
@RunWith(SpringRunner.class)
@SpringBootTest(classes = {GateApp.class, SecurityBeanOverrideConfiguration.class})
public class TenantDomainsMappingIntTest {

@Autowired
private TenantMappingService service;

@Autowired
private TenantDomainRepository tenantDomainRepository;

@Before
public void setup() {

String domainConfig = "---\n"
+ "xm:\n"
+ " - \"test.com\"\n"
+ " - \"bla.bla.com\"\n"
+ " - \"localhost\"\n"
+ "tenant1:\n"
+ " - \"tenant1.COM\"\n"
+ " - \"dev.tenant1.com\"\n";

tenantDomainRepository.onInit(TenantDomainRepository.TENANTS_DOMAINS_CONFIG_KEY, domainConfig);
service.onInit(TenantListRepository.TENANTS_LIST_CONFIG_KEY,
"{\"gate\":[{\"name\":\"tenant2\", \"state\":\"ACTIVE\"}, {\"name\":\"tenant3\", \"state\":\"SUSPENDED\"}]}");
}

@Test
public void test() {

assertNull(service.getTenantKey("unknown"));
assertTrue(service.isTenantPresent("tenant2"));
assertTrue(service.isTenantPresent("tenant3"));
assertTrue(service.isTenantPresent("TENANT3"));
assertFalse(service.isTenantPresent("tenant4"));
assertFalse(service.isTenantPresent(null));

assertTrue(service.isTenantActive("tenant2"));
assertTrue(service.isTenantActive("TENANT2"));
assertFalse(service.isTenantActive("tenant3"));
assertFalse(service.isTenantActive("TENANT3"));
assertFalse(service.isTenantActive("tenant4"));
assertFalse(service.isTenantActive(null));

}

}
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
package com.icthh.xm.gate.web.rest;

import static org.junit.Assert.assertEquals;

import com.icthh.xm.commons.config.client.repository.TenantListRepository;
import com.icthh.xm.gate.GateApp;
import com.icthh.xm.gate.config.SecurityBeanOverrideConfiguration;
Expand All @@ -12,13 +10,18 @@
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.context.junit4.SpringRunner;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;

/**
*
*/
@RunWith(SpringRunner.class)
@SpringBootTest(classes = {GateApp.class, SecurityBeanOverrideConfiguration.class})
@TestPropertySource(properties = "application.redirect-to-default-tenant-enabled=true")
public class TenantDomainsMappingUnitTest {

@Autowired
Expand Down

0 comments on commit 686d776

Please sign in to comment.