Skip to content

Commit

Permalink
add: API Gateway microservice
Browse files Browse the repository at this point in the history
  • Loading branch information
antonioscardace committed Jun 11, 2024
1 parent c6c54d7 commit 4ef63e7
Show file tree
Hide file tree
Showing 5 changed files with 280 additions and 0 deletions.
80 changes: 80 additions & 0 deletions api-gateway/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
<?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>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.2.RELEASE</version>
<relativePath/>
</parent>

<groupId>netwatch</groupId>
<artifactId>gateway</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>gateway</name>
<description>Microservice for providing the API Gateway.</description>

<properties>
<java.version>11</java.version>
<spring-cloud.version>Greenwich.RC2</spring-cloud.version>
</properties>

<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
<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-web</artifactId>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>32.1.3-jre</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.30</version>
<scope>provided</scope>
</dependency>
</dependencies>

<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>

<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>

<repositories>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
</repository>
</repositories>

</project>
21 changes: 21 additions & 0 deletions api-gateway/src/main/java/netwatch/gateway/GatewayApplication.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package netwatch.gateway;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;

@SpringBootApplication
@EnableZuulProxy
public class GatewayApplication {

public static void main(String[] args) {
SpringApplication.run(GatewayApplication.class, args);
}

@Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}
}
113 changes: 113 additions & 0 deletions api-gateway/src/main/java/netwatch/gateway/filters/AuthFilter.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
package netwatch.gateway.filters;

import java.util.Arrays;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;

import com.google.common.util.concurrent.RateLimiter;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;

import lombok.extern.java.Log;

// This class is a Zuul pre-filter responsible for authenticating and authorizing incoming requests.
// It verifies the validity of a token by requesting an Authentication Service.
// It applies the RBAC Pattern by requesting an Authorization Service.
// It includes rate limiting to prevent abuse of the service.
// @author Antonio Scardace
// @version 1.0

@Log
@Component
public class AuthFilter extends ZuulFilter {

private final RestTemplate restTemplate;
private final String authenticationUrl = System.getenv("AUTHN_URL");
private final String authorizationUrl = System.getenv("AUTHZ_URL");
private static RateLimiter rateLimiter = RateLimiter.create(10);

@Autowired
public AuthFilter(RestTemplate restTemplate) {
this.restTemplate = restTemplate;
}

@Override
public String filterType() {
return "pre";
}

@Override
public int filterOrder() {
return 2;
}

@Override
public boolean shouldFilter() {
return true;
}

private boolean checkAuthorization(String userRole, String method, String object) {
String authUrl = this.authorizationUrl + "/check" + "?role=" + userRole + "&method=" + method + "&object=" + object;
return "true".equals(restTemplate.getForObject(authUrl, String.class));
}

private boolean isTokenValid(String apiKey) {
String url = this.authenticationUrl + "/validate/" + apiKey;
return "true".equals(restTemplate.getForObject(url, String.class));
}

private String getUserRole(String apiKey) {
String url = this.authenticationUrl + "/role/" + apiKey;
return restTemplate.getForObject(url, String.class);
}

// Zuul pre-filter for authentication and authorization.
// Checks if the rate limit has been exceeded. If so, responds with a 429 status code.
// Otherwise, proceeds with the authentication and authorization checks.
// If the request is a valid sign-in or sign-up operation the filter allows the request to proceed.
// If the request has a valid API Key and is authorized, the filter allows the request to proceed.
// Otherwise, sets a Zuul response with a 403 Forbidden status, indicating a "Forbidden Request".
// The user authorization verification is based on its role, HTTP method, and requested route.

@Override
public Object run() {
RequestContext context = RequestContext.getCurrentContext();

if (!rateLimiter.tryAcquire(1)) {
context.setSendZuulResponse(false);
context.setResponseStatusCode(429);
context.setResponseBody("Rate limit exceeded.");

log.warning("Rate limit exceeded.");
return null;
}

String apiKey = context.getRequest().getHeader("X-API-Key");
String method = context.getRequest().getMethod();
String uri = context.getRequest().getRequestURI();
String route = uri.substring(context.getRequest().getContextPath().length());

List<String> allowedRoutes = Arrays.asList(
"/authentication/signin",
"/authentication/signup"
);

if ("POST".equals(method) && allowedRoutes.contains(route))
return null;

if (apiKey != null &&
this.isTokenValid(apiKey) &&
this.checkAuthorization(this.getUserRole(apiKey), method, route))
return null;

context.setSendZuulResponse(false);
context.setResponseStatusCode(403);
context.setResponseBody("Forbidden Request.");

log.warning("Forbidden Request: " + method + " " + route);
return null;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package netwatch.gateway.filters;

import org.springframework.stereotype.Component;

import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;

import lombok.extern.java.Log;

// This class is a Zuul pre-filter responsible for logging incoming requests.
// It logs the method and URI of each incoming request.
// This filter receives incoming requests allowed by the Rate Limiter and passes them to other Filters.
// @author Antonio Scardace
// @version 1.0

@Log
@Component
public class LoggingFilter extends ZuulFilter {

@Override
public String filterType() {
return "pre";
}

@Override
public int filterOrder() {
return 1;
}

@Override
public boolean shouldFilter() {
return true;
}

@Override
public Object run() {
RequestContext context = RequestContext.getCurrentContext();
String method = context.getRequest().getMethod();
String uri = context.getRequest().getRequestURI();

log.info("Incoming request: " + method + " " + uri);
return null;
}
}
22 changes: 22 additions & 0 deletions api-gateway/src/main/resources/application.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
server.port = 8888

zuul.routes.idm-users.path = /users/**
zuul.routes.idm-users.url = http://identity-manager:6000/api/users/

zuul.routes.idm-roles.path = /roles/**
zuul.routes.idm-roles.url = http://identity-manager:6000/api/roles/

zuul.routes.idm-authentication.path = /authentication/**
zuul.routes.idm-authentication.url = http://identity-manager:6000/api/authentication/

zuul.routes.idm-authorization.path = /authorization/**
zuul.routes.idm-authorization.url = http://identity-manager:6000/api/authorization/

zuul.routes.manager-contacts.path = /contacts/**
zuul.routes.manager-contacts.url = http://manager:6000/api/contacts/

zuul.routes.manager-utilities.path = /utilities/**
zuul.routes.manager-utilities.url = http://manager:6000/api/utilities/

zuul.routes.manager-observations.path = /observations/**
zuul.routes.manager-observations.url = http://manager:6000/api/observations/

0 comments on commit 4ef63e7

Please sign in to comment.